Recent Discussions
-
Newbie here...
Using Windows 11 Pro version 23H2 ... Am trying to use the Mount-DiskImage command to mount an .iso file, but can't figure out how to do it assigning it a specific drive letter... it seems that it automatically assigns either the next available or -NoDriveLetter (using this parameter) Can Anyone direct me how to accomplish this???7 Views0 likes0 Comments -
PowerShell script to reinstall Windows license key
Greetings, I am new to PowerShell. I was talking with my boss recently about an issue we had following the Windows 11 24H2 update. The Windows license is being deactivated following the update. My boss has written a PowerShell script to resolve this issue but he asked me to see if I can write a script as well to fix the issue. He thought it would be good practice for me to learn PowerShell. So he has tossed me into the deep end and I need to quickly learn to swim; ) I need a script that would reinstall the Windows license key, activate the key, and change the DEP policy to opt out mode. This task is above my skill level and I could use some help. Thanks in advance47 Views0 likes3 Comments -
I can add myself to any Site Owners group via the web but getting Access Denied using PowerShell
Add-SPOUser -Site "https://mysite" -Group "mySite Owners" -LoginName myemail Add-SPOUser : Attempted to perform an unauthorized operation. I can successfully add other users to sites I'm already Owner using the above CMD. Thank you!1.2K Views0 likes5 Comments -
Script to balance AD group membership.
The Security team is using Windows Event Forwarding (WEF) to collect logs from Windows workstations. Using Windows Event Collectors (WEC) pointed to AD groups or computers objects. But there is a maximum number of computers that each WEC can handle. So computers have been manually divided between several AD groups. This is a huge maintenance headache for both the help desk who adds them initially, and the security team that is ultimately responsible for it. Especially during the constant workstation replacement projects. They have requested a script that they can run (Probably nightly with Task Scheduler) to manage this, but I've been having a hard time finding the logic required to pull it off. Basically it needs to take an inventory of several groups, and then distribute the members across those groups evenly (as much as possible). The most relevant script sample I could find was of all things ,this script that Google "AI search" spit out. It was a complete mess of context errors but it gave me somewhere to start. It now works up to the point of the "$MembersToAdd" line. Meaning it appears to hash the members of the groups, remove the right amount from the larger groups, but then it "Cannot validate argument on parameter 'Members'. The argument is null or empty." when trying to add the excessive computers to the other groups. Anyone tried anything like this before, or have an idea of what I can do to fix the end of this script? # Import the Active Directory module Import-Module ActiveDirectory # Get all of the AD groups $groups = Get-ADGroup -Filter { Name -like "TEST-ADGroupMembershipBalance*" } -Properties * # Create a hashtable to store the group membership counts $groupMembershipCounts = @{} # Iterate through each group and get the membership count foreach ($group in $groups) { $groupMembershipCounts[$group.Name] = $group.Members.Count # Get the average group membership count $averageGroupMembershipCount = $groupMembershipCounts.Values | Measure-Object -Average | Select-Object -ExpandProperty Average # Iterate through each group and add or remove members to balance the group membership counts foreach ($group in $groups) { Write-Host $group $group.Members.Count if ($groupMembershipCounts[$group.Name] -gt $averageGroupMembershipCount) { # Remove members from the group $membersToRemove = $group.Members | Sort-Object -Descending | Select-Object -First ($groupMembershipCounts[$group.Name] - $averageGroupMembershipCount) Remove-ADGroupMember -Identity $group -Members $membersToRemove } elseif ($groupMembershipCounts[$group.Name] -lt $averageGroupMembershipCount) { # Add members to the group $membersToAdd = Get-ADComputer -Filter * -SearchBase $group.DistinguishedName | Sort-Object {Get-Random} | Select-Object -First ($averageGroupMembershipCount - $groupMembershipCounts[$group.Name]) Add-ADGroupMember -Identity $group -Members $membersToAdd }363 Views0 likes1 Comment -
Get command status from Active Directory Domain machines
We need to get the status of few commands from a domain environment of around 400 machines. All may be windows 10 and windows 11 machines. Need to run this activity couple of times in a day. This may required few Power Shell commands with admin credentials OR we may run this from GPO. But I don't know where can we save the status result from machines (Power Shell script running is disabled via GPO so we may need to run PowerShell commands directly) Commands status result are required (windows 10/11): - Last Windows update status - Bit Locker installed and configured status - Total Local Admin users - LAPs is installed on not on machine211 Views0 likes4 Comments -
Trying to fetch mail info using Microsoft Graph
# Replace these with your app registration details $tenantId = "" $clientSecret = "" $clientId = "" # OAuth 2.0 token endpoint for your tenant $tokenUrl = "https://login.microsoftonline.com/$tenantId/oauth2/v2.0/token" # Microsoft Graph API base URL $graphApiUrl = "https://graph.microsoft.com/v1.0" # The resource scope we are requesting (Mail.Read, MailboxSettings.Read, User.ReadBasic.All) $scope = "https://graph.microsoft.com/.default" # Request an OAuth 2.0 token from Azure AD using the client credentials flow $tokenResponse = Invoke-RestMethod -Method Post -Uri $tokenUrl -ContentType "application/x-www-form-urlencoded" -Body @{ client_id = $clientId client_secret = $clientSecret scope = $scope grant_type = "client_credentials" } # Extract the access token from the response $accessToken = $tokenResponse.access_token # Headers for authenticated requests to Microsoft Graph $headers = @{ Authorization = "Bearer $accessToken" } # Function to fetch paginated results from Microsoft Graph API function Get-PaginatedData { param ( [Parameter(Mandatory = $true)] [string]$initialUrl ) $results = @() $nextLink = $initialUrl while ($nextLink) { try { $response = Invoke-RestMethod -Uri $nextLink -Headers $headers $results += $response.value # Check if there is more data to fetch if ($response.'@odata.nextLink') { $nextLink = $response.'@odata.nextLink' } else { $nextLink = $null } } catch { # Capture and display detailed error information Write-Host "Error fetching data:" if ($_.Exception.Response -is [System.Net.HttpWebResponse]) { $httpResponse = $_.Exception.Response Write-Host "StatusCode: $($httpResponse.StatusCode)" Write-Host "StatusDescription: $($httpResponse.StatusDescription)" # Read the response stream for detailed error $streamReader = New-Object System.IO.StreamReader($httpResponse.GetResponseStream()) $responseBody = $streamReader.ReadToEnd() Write-Host "Response Body: $responseBody" } else { Write-Host "An unknown error occurred." } break } } return $results } # Function to get all emails for a user function Get-EmailsForUser { param ( [Parameter(Mandatory = $true)] [string]$userPrincipalName ) $mailApiUrl = "$graphApiUrl/users/$userPrincipalName/messages" return Get-PaginatedData -initialUrl $mailApiUrl } # Function to get attachment details for a specific email function Get-AttachmentsForEmail { param ( [Parameter(Mandatory = $true)] [string]$userPrincipalName, [Parameter(Mandatory = $true)] [string]$emailId ) $attachmentApiUrl = "$graphApiUrl/users/$userPrincipalName/messages/$emailId/attachments" return Get-PaginatedData -initialUrl $attachmentApiUrl } # Function to get mailbox settings for a user (including last access time) function Get-MailboxSettings { param ( [Parameter(Mandatory = $true)] [string]$userPrincipalName ) $mailboxSettingsApiUrl = "$graphApiUrl/users/$userPrincipalName/mailboxSettings" $mailboxSettings = Invoke-RestMethod -Uri $mailboxSettingsApiUrl -Headers $headers return $mailboxSettings } # Step 1: Fetch only user mailboxes by filtering on userType eq 'Member' $usersApiUrl = "$graphApiUrl/users?`$filter=userType eq 'Member'" Write-Host "Fetching user mailboxes..." $users = Get-PaginatedData -initialUrl $usersApiUrl if ($users.Count -eq 0) { Write-Host "No user mailboxes found. Aborting script." exit } # Initialize result collection $mailboxDataCollection = @() # Step 2: Loop through each user and gather mailbox data foreach ($user in $users) { $userPrincipalName = $user.userPrincipalName Write-Host "Processing mailbox for $userPrincipalName..." # Initialize user data $mailData = @{ User = $userPrincipalName TotalEmails = 0 TotalAttachments = 0 AttachmentsTypeCount = @{ 'PDF' = 0; 'Word' = 0; 'Excel' = 0; 'PPT' = 0; 'Image' = 0; 'Other' = 0 } LastEmailReceived = $null LastAccessTime = $null } # Get emails for this user $emails = Get-EmailsForUser -userPrincipalName $userPrincipalName foreach ($email in $emails) { $mailData.TotalEmails++ # Track the last email received time if (-not $mailData.LastEmailReceived -or $mailData.LastEmailReceived -lt $email.receivedDateTime) { $mailData.LastEmailReceived = $email.receivedDateTime } # Check for attachments if ($email.hasAttachments) { $attachments = Get-AttachmentsForEmail -userPrincipalName $userPrincipalName -emailId $email.id foreach ($attachment in $attachments) { $mailData.TotalAttachments++ # Determine the type of attachment by file extension if ($attachment.name -match '\.pdf$') { $mailData.AttachmentsTypeCount['PDF']++ } elseif ($attachment.name -match '\.docx?$') { $mailData.AttachmentsTypeCount['Word']++ } elseif ($attachment.name -match '\.xlsx?$') { $mailData.AttachmentsTypeCount['Excel']++ } elseif ($attachment.name -match '\.pptx?$') { $mailData.AttachmentsTypeCount['PPT']++ } elseif ($attachment.contentType -match 'image/') { $mailData.AttachmentsTypeCount['Image']++ } else { $mailData.AttachmentsTypeCount['Other']++ } } } } # Get mailbox settings (last access time) $mailboxSettings = Get-MailboxSettings -userPrincipalName $userPrincipalName $mailData.LastAccessTime = $mailboxSettings.lastSignInDateTime # Add user data to the results $mailboxDataCollection += $mailData } # Step 3: Output results $mailboxDataCollection | Format-Table -AutoSize # Optionally, export the results to CSV $mailboxDataCollection | Export-Csv -Path "MailboxDataReport.csv" -NoTypeInformation My goal is to achieve: Total Numbers of email by each mailbox Total Attachments per email by each mailbox Type of attachments (PDF, Word, Excel, PPT, Image, Etc..) Last access Can someone help me in guiding where i am going wrong i have created azure app with proper permissions but my script is not giving me output as expected.215 Views0 likes2 Comments -
How to do deployment of WSP Solution using PNP Powershell in SharePoint
Looking for sample code details for below mentioned using PNP PowerShell. -Uploading WSP file to Solution gallery of Classic SharePoint site -Installing Solution -Activating the solution -Apply the custom template to SharePoint site. #Below is CSOM based Code - looking for code in PNP Based $fileBytes =[System.IO.File]::ReadAllBytes("D:\CustomTemplate.wsp") $fileCreateInfo = New-Object Microsoft.SharePoint.Client.FileCreationInformation $fileCreateInfo.Content = $fileBytes $fileCreateInfo.Url = $list.RootFolder.ServerRelativeUrl + "/CustomTemplate.wsp" $fileCreateInfo.Overwrite = $true $file = $list.RootFolder.Files.Add($fileCreateInfo) $Ctx.Load($file) $Ctx.ExecuteQuery() $designPackageInfo = New-Object Microsoft.SharePoint.Client.Publishing.DesignPackageInfo $designPackageInfo.PackageName = "CustomTemplate.wsp" $WSP = New-Object Microsoft.SharePoint.Client.Publishing.DesignPackageInfo $WSP.PackageGuid = [System.Guid]::Empty $WSP.PackageName = "CustomTemplate.wsp" $WSP.MajorVersion = 1 $WSP.MinorVersion = 0 $WSPFileURL = $list.RootFolder.ServerRelativeUrl + "/" + "CustomTemplate.wsp"; [Microsoft.SharePoint.Client.Publishing.DesignPackage]::Install($Ctx, $Ctx.Site, $WSP, $WSPFileURL) $Ctx.ExecuteQuery() Write-Host -f Green "`tInstalled the Solution Successfully!" #-------------------------------------------------------------------------------- [Microsoft.SharePoint.Client.Publishing.DesignPackage]::Install($Ctx, $site, $designPackageInfo, $fileCreateInfo.Url) $Ctx.ExecuteQuery() # Below is the main code to activate template and assign home page in site. [Microsoft.SharePoint.Client.Publishing.DesignPackage]::Apply($Ctx, $Ctx.Site, $WSP) $Ctx.ExecuteQuery() $web = $Ctx.Site.RootWeb $templateName = “{E7ED6200-07BF-42F8-94CB-F6560D080DFA}#SZ" $web.ApplyWebTemplate($templateName) $web.update() $Ctx.ExecuteQuery()122 Views0 likes2 Comments -
UserProfile Management with PowerShell
We have an issue where quarterly Nessus scans enumerate vulnerability findings for every user profile on an endpoint. This started me on a path to remove obsolete user profiles to reduce the noise from Nessus. I need to accomplish three things in my final script: 1. set the execution policy to bypass; 2. reset the NTUser.dat to the last write time (if this is not done, the third criteria will not return any hits); 3. find all user profiles older than 60 days and delete them. I did try the GPO to delete profiles older than a certain number of days, but it never removes all of them. I pieced together a script from a couple diff sources and came up with the below. My PowerShell-fu is not that advanced so I am looking for suggestions to make it more efficient. The script works, but I noticed that empty user profile folders at C:\Users\ were left behind. Please advise. Is this a candidate to be made into a function? $ErrorActionPreference = "SilentlyContinue" $Report = $Null $Path = "C:\Users" $UserFolders = $Path | GCI -Directory $currentDate = Get-Date $ageLimit = 60 $userProfiles = Get-ChildItem -Path $Path Set-ExecutionPolicy Bypass -Force ForEach ($UserFolder in $UserFolders) { $UserName = $UserFolder.Name If (Test-Path "$Path\$UserName\NTUSer.dat") { $Dat = Get-Item "$Path\$UserName\NTUSer.dat" -force $DatTime = $Dat.LastWriteTime If ($UserFolder.Name -ne "default") { $Dat.LastWriteTime = $UserFolder.LastWriteTime } } } ForEach ($profile in $userProfiles) { $lastWriteTime = $profile.LastWriteTime $profileAge = ($currentDate - $lastWriteTime).Days If ($profileAge -ge $ageLimit) { Remove-Item -Path $profile.FullName -Recurse -Force } }19 Views0 likes2 Comments -
script to use PowerShell to Report Teams Status, Presence and Reset After Time
I would like to create a powershell script to run against my tenant to report where people have got a Reset Status After time coded in Teams Any suggestions - greatfully received. I can only find commands to show presence.10 Views0 likes2 Comments -
Hash/Array return values
I ran across a difference in return values for built in properties depending on whether collecting with a hash or an array. The code below selects an Excel document and iterates properties. If the $hash variable is set to $false the properties are collected as an array, otherwise as a hash. Script run in ISE for Powershell 5.1. A hash comes up with properties not included if array used. This is not a problem to be solved, per se, but is there an explanation for the difference. $hash = $true #change to $false for array $pop = New-Object -ComObject wscript.shell $FileBrowser = New-Object System.Windows.Forms.OpenFileDialog -Property @{ InitialDirectory = $PSScriptRoot Filter = 'Excel Files (*.xlsx;*.xls)|*.xlsx;*.xls' Title = 'Select Excel File' } $result = $FileBrowser.ShowDialog() If ($result -eq 'Cancel') { $popup = $pop.popup("No File Selected",2,"Closing",4096) exit } $xl = $FileBrowser.FileName $popup = $pop.popup("Iterating Built In Properties for $xl `n Please Wait",4,"Running",4096) $excel = New-Object -ComObject Excel.Application $excel.Visible = $false $workbook = $excel.Workbooks.Open($xl) $binding = "System.Reflection.BindingFlags" -as [type] if ($hash -eq $true) {$props = @{} } else {$props = @() } Foreach($property in $workbook.BuiltInDocumentProperties) { $pn = [System.__ComObject].invokemember("name",$binding::GetProperty,$null,$property,$null) trap [system.exception] { if ($hash -eq $true) { $props.Add($pn,"Value Not Found")} else {$props += "$pn`: Value Not Found"} continue } if ($hash -eq $true) { $props.Add($pn,[System.__ComObject].invokemember("value",$binding::GetProperty,$null,$property,$null)) } else {$props += "$pn`:" + [System.__ComObject].invokemember("value",$binding::GetProperty,$null,$property,$null) } } $excel.quit() $excel = $null $props | FT [gc]::collect() [gc]::WaitForPendingFinalizers() Exit20 Views0 likes0 Comments -
Remove a comma from a CSV file for a particular column only
Hi everyone I have a CSV file that has some bad data in a particular column called ColumnA. ColumnA is a column of names. Some of the names have a comma in it. For example, "Invesco QQQ Trust, Series 1". This extra comma is causing issues when I try to import the file because the delimiter is a comma too (ie CSV). The extra comma in the name needs to be removed. The file is a CSV so commas are needed. I need a Powershell script that removes commas for a particular column (ie ColumnA) and only those commas that are not at the beginning or end of the word. For example: ",Invesco QQQ Trust, Series 1," becomes ",Invesco QQQ Trust, Series 1," The leading and lagging commas are still needed in order to preserve the structure of the CSV. How can I do this in Powershell? Thank you in advance cc: LainRobertsonSolved66 Views0 likes8 Comments -
Remove characters from a file name
Hi everyone I have a bunch of CSV files in a folder that need to be cleaned up. Both the file name and file contents have unneeded apostrophes. I need the apostrophes removed from the file name only. Leave contents untouched. For example, c/test/samp'le.csv becomes c/test/sample.csv. c:/test/Ol' Home.csv becomes c:/test/Ol Home.csv The script needs to look at each file in a given folder and remove the apostrophe if it finds one. Not every filename will have an apostrophe in it. The apostrophe can be anywhere in the name (beginning, end, middle of filename). How would I do this in Powershell? Thank youSolved33 Views0 likes7 Comments -
change the primary address (prefix) distribution list group
change the prefix on the primary address distribution list group how to bulk change primary smtp address distribution list group (before @ / prefix) with powershell? can use csv file? if possible, what is the csv format and how is the script? please help, thank you.Solved212 Views0 likes4 Comments -
M365 Exchange & Shared Mailbox Calendar Notifications
M365 Business Premium tenant here. We have a shared mailbox (not resource mailbox) called meetings@ The aim is to have an anonymous email address staff can send out meeting requests to our clients and have a dedicated calandar for those meetings. I've set up the staff members with Receive and SendAs permissions so everyone can set up meetings using that account so that the meeting invite appears to come from meetings@ instead of the staff members email address. Staff can create meetings and the invite is anonymous so that part is working as planned. The problem is, all the staff gets flooded with Accept/Decline messages going to their personal mailboxes. Is there a way to set it so that only the shared mailbox gets the notifications or even supress those messages entirely. I've resorted to email rules for each staff member to either block or divert the messages but I'd really prefer it if there was a one stop shop rahter than having to configure individual's mailboxes to block them. I tried Set-CalendarProcessing -Identity "email address removed for privacy reasons" -RemoveForwardedMeetingNotifications $true -AutomateProcessing AutoUpdate but it didn't seem to do much. Any other ideas?10 Views0 likes0 Comments -
Windows Restricted User Experience Set-CimInstance Error
So I'm trying to set up a restricted user experience that allows the usage of only one application. However, I keep running into this weird error message that provides no useful information: I've been successful in getting the boilerplate example fromthe official Windows guide to work, so I'm fairly certain the error lies in how I've set up the Allowed Apps and PinnedList. Perhaps in the path to the app? But I'm not sure how I'd go about changing that since I got the pathway from the task manager. Any help is appreciated! Full code below: psexec.exe -i -s powershell.exe $assignedAccessConfiguration = @" <?xml version="1.0" encoding="utf-8"?> <AssignedAccessConfiguration xmlns="http://schemas.microsoft.com/AssignedAccess/2017/config" xmlns:rs5="http://schemas.microsoft.com/AssignedAccess/201810/config" xmlns:v3="http://schemas.microsoft.com/AssignedAccess/2020/config" xmlns:v5="http://schemas.microsoft.com/AssignedAccess/2022/config"> <Profiles> <Profile Id="{9A2A490F-10F6-4764-974A-43B19E722C24}"> <AllAppsList> <AllowedApps> <App AppUserModelId="Microsoft.RemoteDesktop_10.2.3012.0_x64__8wekyb3d8bbwe" /> </AllowedApps> </AllAppsList> <v5:StartPins><![CDATA[{ "pinnedList":[ {"packagedAppId":"Microsoft.RemoteDesktop_10.2.3012.0_x64__8wekyb3d8bbwe"}, }]]></v5:StartPins> <Taskbar ShowTaskbar="true" /> </Profile> </Profiles> <Configs> <Config> <AutoLogonAccount rs5:DisplayName="RDUSER" /> <DefaultProfile Id="{9A2A490F-10F6-4764-974A-43B19E722C24}" /> </Config> </Configs> </AssignedAccessConfiguration>