Forum Widgets
Latest Discussions
Can't add device member in Static Security Entra Group with powershell
Hi, With Graph, I want to add some device members in a static security Entra group using it to deploy some certificates with Intune. I do it with following command: New-MgGroupMember -GroupId $groupId -DirectoryObjectId $device.AzureAdDeviceId but I receive this error: New-MgGroupMember : Resource 'df75dfe1-8b5a-4cc6-8f99-17746bb8c07e' does not exist or one of its queried reference-property objects are not present. In C:\Users\E21996\OneDrive - Fondazione Enasarco\Lavoro\!HelpDesk\!Intune\Scripts\Set-Device-Department-Attribute.ps1:57 car:9 + New-MgGroupMember -GroupId $groupId -DirectoryObjectId $devic ... + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + CategoryInfo : InvalidOperation: ({ GroupId = 9fa...ferenceCreate }:<>f__AnonymousType1`2) [New-MgGroupMember_CreateExpanded], Exception + FullyQualifiedErrorId : Request_ResourceNotFound,Microsoft.Graph.PowerShell.Cmdlets.NewMgGroupMember_CreateExpanded I've checked the GroupID and Azure Device ID and are correct. If I try to add a user it works fine, with device I have this error. In the group I can add device member manually from Intune without problems. There is a known issue when add device members to groups in Graph? Can anyone help me to resolve this issue, please?LUCA NAVIGLIOOct 09, 2025Copper Contributor89Views0likes2CommentsNew-MgBookingBusinessService | Turn Customer Information Questions Off
I'm trying to turn off the stock Customer information questions except for customer email but cannot find how to do it? Any support is much appreciated. Below is what I've recently tried... # Prompt for Booking Business ID $bookingBusinessId = Read-Host "Enter the Booking Business ID (e.g., email address removed for privacy reasons)" # Prompt for default duration in minutes $defaultDurationMinutes = Read-Host "Enter default appointment duration in minutes (e.g., 15)" $defaultDuration = [TimeSpan]::FromMinutes([double]$defaultDurationMinutes) # Post-buffer stays at 5 minutes $postBuffer = [TimeSpan]::FromMinutes(5) # Hardcoded Excel file path $excelFilePath = "C:\Users\apettit\OneDrive - Eau Claire Area School District\Downloads\adamtestconferencedata.xlsx" # Prompt for worksheet/tab name $sheetName = Read-Host "Enter the worksheet/tab name to read data from" # Import Excel data using Import-Excel (requires ImportExcel module) if (-not (Get-Module -ListAvailable -Name ImportExcel)) { Install-Module -Name ImportExcel -Scope CurrentUser -Force } Import-Module ImportExcel $staffEmails = Import-Excel -Path $excelFilePath -WorksheetName $sheetName # Retrieve all staff members for the booking business Write-Host "Fetching all staff members for booking business ID: $bookingBusinessId" $allStaff = Get-MgBookingBusinessStaffMember -BookingBusinessId $bookingBusinessId if (-not $allStaff) { Write-Error "No staff members found for the booking business ID: $bookingBusinessId" return } # Retrieve all custom questions Write-Host "Fetching all custom questions for booking business ID: $bookingBusinessId" $allCustomQuestions = Get-MgBookingBusinessCustomQuestion -BookingBusinessId $bookingBusinessId if (-not $allCustomQuestions) { Write-Error "No custom questions found for the booking business ID: $bookingBusinessId" return } # Loop through each staff member from Excel automatically Write-Host "Creating individual booking services for each staff member..." foreach ($row in $staffEmails) { $email = $row.emailAddress.Trim().ToLower() # Automatically match staff from Booking Business $matchingStaff = $allStaff | Where-Object { $_.AdditionalProperties["emailAddress"] -and ($_.AdditionalProperties["emailAddress"].Trim().ToLower() -eq $email) } if ($matchingStaff) { $staffId = $matchingStaff.Id $displayName = $matchingStaff.AdditionalProperties["displayName"] Write-Host "Automatically creating service for: ${displayName} ($email)" -ForegroundColor Cyan try { # Prepare custom questions $customQuestions = $allCustomQuestions | ForEach-Object -Begin { $isLast = $false } -Process { $isLast = ($_.Id -eq $allCustomQuestions[-1].Id) $questionAssignment = New-Object Microsoft.Graph.PowerShell.Models.MicrosoftGraphBookingQuestionAssignment $questionAssignment.QuestionId = $_.Id $questionAssignment.IsRequired = if ($isLast) { $false } else { $true } $questionAssignment } # Prepare the reminder $defaultReminder = New-Object Microsoft.Graph.PowerShell.Models.MicrosoftGraphBookingReminder $defaultReminder.Message = "Don't forget! Family Teacher Conferences are tomorrow, and we are excited to visit with you! If you wish to change the meeting type (virtual, in-person, hybrid, or phone), please let the teacher know as soon as possible!" $defaultReminder.Offset = [TimeSpan]::FromDays(1) $defaultReminder.Recipients = @("customer") # Prepare service parameters $serviceParams = @{ BookingBusinessId = $bookingBusinessId DisplayName = "${displayName} Family Conference" Description = "Family Teacher Conference with ${displayName}" StaffMemberIds = @($staffId) # Assign specific staff member DefaultDuration = $defaultDuration DefaultPrice = 0.00 DefaultPriceType = "free" CustomQuestions = $customQuestions PostBuffer = $postBuffer IsLocationOnline = $true IsCustomerAllowedToManageBooking = $true DefaultReminder = $defaultReminder AdditionalInformation = @" Please arrive on time for your conferences as we will be sticking to a tight schedule. If you wish to change the meeting type (virtual, in-person, hybrid, or phone), please let the teacher know as soon as possible. If you require a translator, please submit a request at this form: https://forms.office.com/r/ "@ # Appears in the customer confirmation email } # Log service parameters Write-Host "Service Parameters for ${displayName}:" -ForegroundColor Blue $serviceParams.GetEnumerator() | ForEach-Object { Write-Host "$($_.Key): $($_.Value)" } # Create the booking service New-MgBookingBusinessService @serviceParams Write-Host "Booking service successfully created for ${displayName}!" -ForegroundColor Green } catch { Write-Error "Failed to create booking service for ${displayName}: $_" } } else { Write-Warning "No match found for email: $email" } }AP_TC_ECASDOct 05, 2025Brass Contributor32Views0likes2CommentsNew-MgBookingBusinessService | Customer Information Questions
I'm trying to turn off the stock Customer Information questions except for the customer email using PowerShell and New-MgBookingBusinessService and cannot seem to figure it out. Any assistance is much appreciated! # Prompt for Booking Business ID $bookingBusinessId = Read-Host "Enter the Booking Business ID (e.g., email address removed for privacy reasons)" # Prompt for default duration in minutes $defaultDurationMinutes = Read-Host "Enter default appointment duration in minutes (e.g., 15)" $defaultDuration = [TimeSpan]::FromMinutes([double]$defaultDurationMinutes) # Post-buffer stays at 5 minutes $postBuffer = [TimeSpan]::FromMinutes(5) # Hardcoded Excel file path $excelFilePath = "C:\Users\apettit\OneDrive - Eau Claire Area School District\Downloads\adamtestconferencedata.xlsx" # Prompt for worksheet/tab name $sheetName = Read-Host "Enter the worksheet/tab name to read data from" # Import Excel data using Import-Excel (requires ImportExcel module) if (-not (Get-Module -ListAvailable -Name ImportExcel)) { Install-Module -Name ImportExcel -Scope CurrentUser -Force } Import-Module ImportExcel $staffEmails = Import-Excel -Path $excelFilePath -WorksheetName $sheetName # Retrieve all staff members for the booking business Write-Host "Fetching all staff members for booking business ID: $bookingBusinessId" $allStaff = Get-MgBookingBusinessStaffMember -BookingBusinessId $bookingBusinessId if (-not $allStaff) { Write-Error "No staff members found for the booking business ID: $bookingBusinessId" return } # Retrieve all custom questions Write-Host "Fetching all custom questions for booking business ID: $bookingBusinessId" $allCustomQuestions = Get-MgBookingBusinessCustomQuestion -BookingBusinessId $bookingBusinessId if (-not $allCustomQuestions) { Write-Error "No custom questions found for the booking business ID: $bookingBusinessId" return } # Loop through each staff member from Excel automatically Write-Host "Creating individual booking services for each staff member..." foreach ($row in $staffEmails) { $email = $row.emailAddress.Trim().ToLower() # Automatically match staff from Booking Business $matchingStaff = $allStaff | Where-Object { $_.AdditionalProperties["emailAddress"] -and ($_.AdditionalProperties["emailAddress"].Trim().ToLower() -eq $email) } if ($matchingStaff) { $staffId = $matchingStaff.Id $displayName = $matchingStaff.AdditionalProperties["displayName"] Write-Host "Automatically creating service for: ${displayName} ($email)" -ForegroundColor Cyan try { # Prepare custom questions $customQuestions = $allCustomQuestions | ForEach-Object -Begin { $isLast = $false } -Process { $isLast = ($_.Id -eq $allCustomQuestions[-1].Id) $questionAssignment = New-Object Microsoft.Graph.PowerShell.Models.MicrosoftGraphBookingQuestionAssignment $questionAssignment.QuestionId = $_.Id $questionAssignment.IsRequired = if ($isLast) { $false } else { $true } $questionAssignment } # Prepare the reminder $defaultReminder = New-Object Microsoft.Graph.PowerShell.Models.MicrosoftGraphBookingReminder $defaultReminder.Message = "Don't forget! Family Teacher Conferences are tomorrow, and we are excited to visit with you! If you wish to change the meeting type (virtual, in-person, hybrid, or phone), please let the teacher know as soon as possible!" $defaultReminder.Offset = [TimeSpan]::FromDays(1) $defaultReminder.Recipients = @("customer") # Prepare service parameters $serviceParams = @{ BookingBusinessId = $bookingBusinessId DisplayName = "${displayName} Family Conference" Description = "Family Teacher Conference with ${displayName}" StaffMemberIds = @($staffId) # Assign specific staff member DefaultDuration = $defaultDuration DefaultPrice = 0.00 DefaultPriceType = "free" CustomQuestions = $customQuestions PostBuffer = $postBuffer IsLocationOnline = $true IsCustomerAllowedToManageBooking = $true DefaultReminder = $defaultReminder AdditionalInformation = @" Please arrive on time for your conferences as we will be sticking to a tight schedule. If you wish to change the meeting type (virtual, in-person, hybrid, or phone), please let the teacher know as soon as possible. If you require a translator, please submit a request at this form: https://forms.office.com/r/XWwBFWP7XD "@ # Appears in the customer confirmation email AdditionalProperties = @{ customerEmail = @{ isRequired = $true } # Only email field remains } } # Log service parameters Write-Host "Service Parameters for ${displayName}:" -ForegroundColor Blue $serviceParams.GetEnumerator() | ForEach-Object { Write-Host "$($_.Key): $($_.Value)" } # Create the booking service New-MgBookingBusinessService @serviceParams Write-Host "Booking service successfully created for ${displayName}!" -ForegroundColor Green } catch { Write-Error "Failed to create booking service for ${displayName}: $_" } } else { Write-Warning "No match found for email: $email" } }AP_TC_ECASDSep 30, 2025Brass Contributor7Views0likes0CommentsCreating Claims Mapping Policy in Entra ID
I am attempting to create a Claims Mapping Policy using PowerShell, Entra ID and Microsoft Graph via a script or a PowerShell Window, In neither case, I was able to do it. The script is: # Define the Application (Client) ID and Secret $applicationClientId = 'XXXXXXXXXXX' # Application (Client) ID $applicationClientSecret = 'XXXXXXXXXXX' # Application Secret Value $tenantId = 'XXXXXXXXXXXX' # Tenant ID Connect-Entra -TenantId $tenantId -ClientSecretCredential $clientSecretCredential $params = @{ definition = @( '{"ClaimsMappingPolicy":{"Version":1,"IncludeBasicClaimSet":"false","ClaimsSchema":[{"Source":"user","onpremisesssamaccountname":"name","SamlClaimType": "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/name"}]}}' ) displayName = "ClaimTest" } New-MgPolicyClaimMappingPolicy -BodyParameter $params Get-MgPolicyClaimMappingPolicy Disconnect-Entra I keep getting the error: New-MgPolicyClaimMappingPolicy : One or more errors occurred. At C:\Users\eigog\Documents\Poweshell Scripts\test.ps1:24 char:1 + New-MgPolicyClaimMappingPolicy -BodyParameter $params + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + CategoryInfo : NotSpecified: (:) [New-MgPolicyClaimMappingPolicy_Create], AggregateException + FullyQualifiedErrorId : System.AggregateException,Microsoft.Graph.PowerShell.Cmdlets.NewMgPolicyClaimMappingPolicy_Create I don't understand, because this was similar to the example they gave here: https://learn.microsoft.com/en-us/entra/identity-platform/claims-customization-powershell And yes, I tried to do it manually in a PowerShell window with my credentials and I tried the beta version as well. The application does have the scope of Policy.ReadWrite.ApplicationConfiguration. I can't seem to see the error. Can anyone see something I'm missing or point me in a direction? ThanksSolvedMustangProgrammerSep 30, 2025Copper Contributor28Views0likes1CommentWhy does this return a .csv with the length of the group names?
Hi, I've been trying to list the names of the Entra groups a user is a member of. Most of the scripts I've found online will only display the group ID and leaves the other fields blank, if they show up at all. I found this command works in the terminal: Get-MgUserMemberOf -UserId $userPrincipalName | % {($_.AdditionalProperties).displayName} However, when I try to export it to CSV is get a single column named "Length" and a number in each row which I believe corresponds to the lenght of the group name in characters. Here's the full command: Get-MgUserMemberOf -UserId $userPrincipalName | % {($_.AdditionalProperties).displayName} | Export-Csv -Path "C:\Temp\GroupMemberships.csv" -NoTypeInformation What am I doing wrong?kcelmerSep 23, 2025Brass Contributor74Views0likes4CommentsProblem restoring deleted user with mggraph
Hello, I have done a few 365 migration and almost everytime there are some user data that has been missed in the migration. Earlier I solved this by restoring the 365 user in the source tenant to another domain using this msol script in powershell: Restore-MsolUser -UserPrincipalName email address removed for privacy reasons -Verbose Restore-MsolUser -UserPrincipalName email address removed for privacy reasons -Verbose -AutoReconcileProxyConflicts Restore-MsolUser -UserPrincipalName email address removed for privacy reasons -Verbose -AutoReconcileProxyConflicts -NewUserPrincipalName email address removed for privacy reasons I know it is not perfect but it worked well and saved a bunch of times. I have now done another migration now and got the same issue so I need to restore the users so we can access the data again and move it. BUT! I realized today that msol service is no more, so I am kinda stuck with figuring this out in mggraph. I have tried for a few hours now and I am not sure if this even possible with mggraph. Whenever I try to build a script using Restore-MgDirectoryDeletedUser/Item which google, copilote etc tells me to use I only get this error: The term 'Restore-MgDirectoryDeletedUser/item' is not recognized as the name of a cmdlet, function, script file, or operable program. Check the spelling of the name, or if a path was included, verify that the path is correct and try again. Or I get that it "works" but that the proxy/domain conflicts: Errors detected while trying to restore the user restoreUserErrors: ErrorValue:<pii><pii>E*****.E*******</pii>@domain.com</pii> ObjectType: ConflictingObjectId:, ErrorType:UserPrincipalName, ErrorId:InvalidDomainErrorValue:<pii>smtp:<pii>ee</pii>@domain.com</pii> ObjectType: ConflictingObjectId:, ErrorType:ProxyAddress, ErrorId:InvalidDomain Status: 400 (BadRequest) ErrorCode: Request_BadRequest Date: 2025-09-08T13:49:36 Since I do not have the first domain in the source tenant anymore I need to restore the user to a different domain. Does anyone have any idea on how I can recreate the msol version to mggraph? I feel like I have tried everything to my knowledge now so hopefully anyone here can give me help or tips. Thanks! /AdamAdamneedshelpwithpowershellSep 20, 2025Copper Contributor170Views0likes5CommentsWhere can I find a lots of scripts like Script Guy site used to have?
Hi, I am sorry if this is a bit of easy post but the internet appears to be so spread out these days and de-centralised from what it used to be. I am looking for a site that has lots of good scripts similar to the good old Script Guy site. Please can you help. ThanksmidimanSep 19, 2025Copper Contributor2.5KViews2likes3CommentsUnleashing Parallelism in PowerShell
This blog on my site got a lot of possitive feedback. Hopefully it can help others as well hence I share it here. If you want to check more check my blog on: https://bartpasmans.tech/ or check my LinkedIn: https://www.linkedin.com/in/bart-pasmans-6533094b/ Unleashing Parallelism in PowerShell If you’ve been around PowerShell for a while, you know it’s great at looping through stuff. Need to process a list of files? Easy. Query a set of servers? Piece of cake. But sometimes… you hit a wall. The problem? Sequential execution. By default, your loops work in a single-file line, like shoppers at a small-town bakery. That’s fine for five people. Not so fine for five thousand. That’s where ForEach-Object -Parallel enters the chat. 🚀 This feature, introduced in PowerShell 7, lets you process multiple items at the same time, tapping into all those CPU cores just sitting there looking bored. Today, we’re going to walk through how it works, why it’s a game-changer, and where you should (and shouldn’t) use it. We’ll keep it hands-on, so keep PowerShell open! you’ll see the 🎬 icon whenever it’s time to get your hands dirty. Today’s Toolbelt Here’s the deal: ForEach-Object -Parallel is like the express checkout lane at the grocery store. Instead of every task waiting for the one ahead to finish, they all get their own lane. We’ll explore: Basic parallel loops – Using ForEach-Object -Parallel in the simplest form Passing variables – How to get data into your parallel script block Controlling thread counts – Because unlimited parallelism can get… messy Real-world scenarios – Places where it shines (and where it doesn’t) Why Parallel? Imagine you have 50 servers to check for a certain log file. Running them one after another takes… forever. With parallel processing, you can hit multiple servers at once, finishing in a fraction of the time. 📒 Under the hood: PowerShell spins up runspaces, lightweight, isolated environment, to execute each chunk of work simultaneously. It’s not “true” OS-level multithreading, but it’s incredibly efficient for I/O-bound tasks like network calls, file reads, or API requests. 1..5 | ForEach-Object -Parallel { Start-Sleep -Seconds 1 "Task $_ completed on thread $([System.Threading.Thread]::CurrentThread.ManagedThreadId)" } What’s happening: 1..5 gives us five items. Each item is processed in a parallel runspace. They all sleep for one second…. 🥁🥁🥁 but because they run in parallel, the whole thing finishes in just over a second, not five! My previous blog: https://bartpasmans.tech/start-scripting-like-a-pro-6-speeding-up-your-code/ I showed you how to make your own threads and consume them. Check it out! 😊 This blog sticks with PowerShell cmdlets natively. Passing Data Into Parallel Blocks One catch with ForEach-Object -Parallel: it runs in its own scope. Your outer variables aren’t magically available inside. 🎬 Here’s how to pass variables in: $prefix = "Server" 1..3 | ForEach-Object -Parallel { "$using:prefix-$($_)" } 📒 The magic word: $using: tells PowerShell to bring in a variable from outside the parallel block. Controlling the Chaos Yes, parallelism is powerful, but if you let 200 jobs spin up at once, you might as well be starting a tiny CPU apocalypse 💣. 🎬 Throttle it with 1..10 | ForEach-Object -Parallel { Start-Sleep -Seconds 2 "Processed $_" } -ThrottleLimit 3 Here, only three parallel tasks run at a time. As soon as one finishes, the next starts. Real-World Example: Network Ping 🎬 Checking multiple hosts in parallel: $servers = "server1","server2","server3","server4","server5" $servers | ForEach-Object -Parallel { $result = Test-Connection -ComputerName $_ -Count 1 -Quiet "$_ is " + ($(if ($result) { "online" } else { "offline" })) } -ThrottleLimit 2 The pings happen two at a time. Overall time drops drastically compared to running sequentially. When Not to Use It 📒 Parallelism is not a free lunch. If your task is super short and light (like adding numbers), spinning up runspaces is actually slower. For CPU-heavy operations, you might saturate your system quickly. Avoid it when order matters—parallel execution doesn’t guarantee output order unless you take extra steps. Summary Wrapping It Up! PowerShell Meets Parallelism 🎉 Today we saw how ForEach-Object -Parallel lets you take PowerShell’s already-great iteration abilities and put them into warp speed. We covered: The basics of parallel loops Passing variables with $using: Throttling to keep your system happy Real-world use cases like pinging servers The takeaway? When you’re faced with a big list of time-consuming tasks, don’t just wait your turn in the single checkout lane. Open more lanes with ForEach-Object -Parallel! Just remember that more isn’t always better. Got your own clever use for parallel loops? Share it, I love seeing how people bend PowerShell to their will. Until next time! Keep automating, keep experimenting, and keep pushing your scripts to the next level. 🚀☕🍰Bart_PasmansSep 15, 2025Copper Contributor25Views1like0CommentsError setting profile for interface Primary LAN Interface
Hi all I have a problem with this script. It says "Error setting profile for interface Primary LAN Interface: The network connection profile is corrupted". I need to set the Network card Protected EAP Properties to "Smartcard or other certificate" and set the Trusted Root Certification Autorities to use our Root certificate. Is there any other way to automate this or can you help me finding the problem in this script? Thanks for your help! Powershell Script: # ================================ # 802.1X PEAP (EAP-TLS) for Wired # Interface: "Primary LAN Interface" # Root CA can be selected by Thumbprint or Subject Match # Run as Administrator # ================================ $InterfaceName = "Primary LAN Interface" # Target NIC display name $ProfileName = "Network" # Wired profile name to manage $TempFolder = "D:\iltis\tools\Temp\LanProfile" # Root CA selection (choose ONE approach) $RootCAThumbprint = "96f2bf58b39db8b704a4dda8c5df456c725fce24" # e.g. "AB12CD34EF56..."; leave blank to use subject search $RootCASubjectLike = "Root" # Used only if $RootCAThumbprint is blank # ---------- Helpers ---------- function Ensure-Folder($path) { if (-not (Test-Path $path)) { New-Item -ItemType Directory -Path $path | Out-Null } } function Get-RootCAThumbprint { param( [string]$Thumbprint, [string]$SubjectLike ) if ($Thumbprint -and $Thumbprint.Trim() -ne "") { return ($Thumbprint -replace "\s","").ToUpper() } $match = Get-ChildItem Cert:\LocalMachine\Root | Where-Object { $_.Subject -like "*$SubjectLike*" } | Select-Object -First 1 if (-not $match) { throw "Root CA with subject like '$SubjectLike' not found in LocalMachine\Root." } return ($match.Thumbprint -replace "\s","").ToUpper() } function Start-WiredAutoConfig { $svc = Get-Service -Name dot3svc -ErrorAction SilentlyContinue if (-not $svc) { throw "Wired AutoConfig (dot3svc) service not found." } if ($svc.StartType -ne 'Automatic') { Set-Service dot3svc -StartupType Automatic } if ($svc.Status -ne 'Running') { Start-Service dot3svc } } function Get-NicOrThrow { param([string]$Name) $nic = Get-NetAdapter -Name $Name -ErrorAction SilentlyContinue if (-not $nic) { throw "Network adapter '$Name' not found. Use Get-NetAdapter to confirm the exact name." } if ($nic.Status -ne 'Up') { Write-Warning "Adapter '$Name' is not Up (status: $($nic.Status)). Continuing anyway." } return $nic } # Minimal valid LAN profile XML with EAPHostConfig placeholder (we’ll inject the Root CA thumbprint). function New-LanProfileXml { param([string]$ProfName) @" <?xml version="1.0"?> <LANProfile xmlns="http://www.microsoft.com/networking/LAN/profile/v1"> <name>$ProfName</name> <MSM> <security> <OneX xmlns="http://www.microsoft.com/networking/OneX/v1"> <authMode>userOrComputer</authMode> <EAPConfig> <EapHostConfig xmlns="http://www.microsoft.com/provisioning/EapHostConfig"> <EapMethod> <Type xmlns="http://www.microsoft.com/provisioning/EapCommon">25</Type> <AuthorId xmlns="http://www.microsoft.com/provisioning/EapCommon">0</AuthorId> </EapMethod> <Config xmlns="http://www.microsoft.com/provisioning/EapHostConfig"> <Eap xmlns="http://www.microsoft.com/provisioning/BaseEapConnectionPropertiesV1"> <Type>13</Type> <EapType xmlns="http://www.microsoft.com/provisioning/EapTlsConnectionPropertiesV1"> <CredentialsSource> <CertificateStore> <SimpleCertSelection>true</SimpleCertSelection> </CertificateStore> </CredentialsSource> <ServerValidation> <DisableUserPromptForServerValidation>true</DisableUserPromptForServerValidation> <ServerNames></ServerNames> <TrustedRootCA>__ROOT_CA_THUMBPRINT__</TrustedRootCA> </ServerValidation> <DifferentUsername>false</DifferentUsername> </EapType> </Eap> </Config> </EapHostConfig> </EAPConfig> </OneX> </security> </MSM> </LANProfile> "@ } # ---------- Main ---------- try { Write-Host "Preparing environment..." -ForegroundColor Cyan Ensure-Folder $TempFolder Start-WiredAutoConfig $null = Get-NicOrThrow -Name $InterfaceName $thumb = Get-RootCAThumbprint -Thumbprint $RootCAThumbprint -SubjectLike $RootCASubjectLike Write-Host "Using Root CA Thumbprint: $thumb" -ForegroundColor Green # Try to export existing profile for this interface+name; if missing, build a fresh one. $exported = $false Write-Host "Exporting existing wired profile (if present)..." -ForegroundColor Cyan $null = netsh lan export profile folder="$TempFolder" interface="$InterfaceName" name="$ProfileName" 2>$null $ProfilePath = Join-Path $TempFolder "$ProfileName.xml" if (Test-Path $ProfilePath) { $exported = $true } if (-not $exported) { Write-Host "No existing profile named '$ProfileName' found. Creating a new one..." -ForegroundColor Yellow $xmlText = New-LanProfileXml -ProfName $ProfileName $xmlText = $xmlText -replace "__ROOT_CA_THUMBPRINT__", $thumb $xmlText | Set-Content -Path $ProfilePath -Encoding UTF8 } else { # Load existing, replace EAP host config with our desired PEAP->EAP-TLS block [xml]$xml = Get-Content $ProfilePath # Find any EapHostConfig node and replace its InnerXml with our config (PEAP 25 -> inner EAP-TLS 13) $ns = New-Object System.Xml.XmlNamespaceManager($xml.NameTable) $ns.AddNamespace("lp", "http://www.microsoft.com/networking/LAN/profile/v1") $ns.AddNamespace("ox", "http://www.microsoft.com/networking/OneX/v1") $eapConfigNode = $xml.SelectSingleNode("//lp:LANProfile/lp:MSM/lp:security/ox:OneX/ox:EAPConfig", $ns) if (-not $eapConfigNode) { throw "EAPConfig node not found in exported profile. Cannot proceed safely." } $newEap = New-LanProfileXml -ProfName $ProfileName # extract just the EAPHostConfig from the template [xml]$tmp = $newEap $tmpNs = New-Object System.Xml.XmlNamespaceManager($tmp.NameTable) $tmpNs.AddNamespace("lp", "http://www.microsoft.com/networking/LAN/profile/v1") $tmpNs.AddNamespace("ox", "http://www.microsoft.com/networking/OneX/v1") $eapHostConfig = $tmp.SelectSingleNode("//lp:LANProfile/lp:MSM/lp:security/ox:OneX/ox:EAPConfig/*", $tmpNs) # Replace placeholder with real thumbprint $eapHostConfigOuterXml = $eapHostConfig.OuterXml.Replace("__ROOT_CA_THUMBPRINT__", $thumb) # Replace EAPConfig contents $eapConfigNode.InnerXml = $eapHostConfigOuterXml # Save back $xml.Save($ProfilePath) } Write-Host "Importing wired 802.1X profile to '$InterfaceName'..." -ForegroundColor Cyan # Adds the profile and associates it with the specified interface netsh lan add profile filename="$ProfilePath" interface="$InterfaceName" # Optional: force 802.1X reauth/reconnect try { netsh lan reconnect interface="$InterfaceName" | Out-Null } catch {} Write-Host "" Write-Host "✅ Done." -ForegroundColor Green Write-Host "The adapter '$InterfaceName' is configured for PEAP with inner 'Smart Card or other certificate' (EAP-TLS) and trusts the specified Root CA." -ForegroundColor Green Write-Host "Profile name: $ProfileName" Write-Host "" Write-Host "Tip: If your NAC expects machine auth, make sure a valid machine certificate is present in LocalMachine\My." -ForegroundColor DarkGray } catch { Write-Error $_.Exception.Message exit 1 }Tomcat456Aug 28, 2025Copper Contributor97Views0likes2Comments
Resources
Tags
- Windows PowerShell1,189 Topics
- powershell344 Topics
- office 365280 Topics
- azure active directory144 Topics
- sharepoint131 Topics
- Windows Server129 Topics
- azure98 Topics
- exchange97 Topics
- community54 Topics
- azure automation50 Topics