Exchange Server - Get CASMailbox - Parameters - exchange-server

When Running a Get CASMailbox command in the Exchange Management Shell, is there a parameter that will return a list of acttive and disabled mailboxes?

This might serve your purpose if you haven't already found the answer:
Get-CASMailbox -Filter {HasActiveSyncDevicePartnership -eq $True -and DisplayName -notlike "CAS_{*"}

Related

Powershell script CPU usage high

I've got a simple script that looks for a file across a bunch of servers. Issue is that on each server it is pegging CPU and causing issues for production workloads. How can I get this script to not DDoS my machines?!
Start-transcript C:\tools\Querylog.txt
$Servers = Get-ADComputer -Filter {(OperatingSystem -like "*windows*server*") -and (Enabled -eq "True")} -Properties OperatingSystem
Invoke-command -ComputerName $Server-ScriptBlock {Get-ChildItem -Path $_.Root -Recurse -Force -File -ErrorAction SilentlyContinue | Where-Object { $_.Name -like '*somefile-readme*' } |Out-File -FilePath <filePath>\results.txt -Append}
Stop-Transcript
Use the -Filter option with Get-ChildItem, it should be much more performant than returning all objects and filtering with Where-Object.
Also, not related to your CPU issue but in how you are crafting your Get-ADComputer call, you should use a String, not a ScriptBlock for the -Filter arguments on these cmdlets. From that answer:
-Filter doesn't support ScriptBlocks, but they Kind of Work Sometimes™ because they get ToString'd before getting evaluated. They will technically work if you use simple variable expansion like $_ or $emailAddress, but it will eventually cause you a headache, especially if you try to access an object property (like above) because it simply won't work. Use a string filter every time, and if you need to use an object property as a filter parameter, use Variable Substitution or Command Substitution.

How to get only the uptime of the server on Powershell?

I have the following code, It's work when I use directly within powershell:
Get-WmiObject win32_operatingsystem | select #{LABEL=’LastBootUpTime’;EXPRESSION={$_.ConverttoDateTime($_.lastbootuptime)
And it returns:
LastBootUpTime
--------------
14/09/2019 10:41:50
But when I use the command within a Powershell script .ps1 with invoke-command the output returns more informations:
LastBootUpTime PSComputerName RunspaceId
-------------- -------------- ----------
9/14/2019 10:41:50 AM 192.168.0.20 af08d2d8-c4f1-4f85-9d6c-e3f4ffe475c6
Why this happen?
If possible, I'd like without the header LastBootUpTime too.
Invoke-Command will always return additional information, in this case where the command was run and the runspace id. You can always get results into a variable and simply print out the property you want.E.g.
$result = invoke-command {your-command}
$result.LastBootUpTime
or for short
(invoke-command {your-command}).LastBootupTime
Note that when you are using wmi, you do not need to necessarily use invoke-command, you can also directly pass -computer parameter to it to run the command against a remote computer:
Get-WmiObject win32_operatingsystem -computer "remote_computer_name"
Since you're ultimately only interested in the (transformed) property value, there's no need to use Select-Object (whose alias is select) at all - use ForEach-Object instead:
Get-WmiObject Win32_OperatingSystem |
ForEach-Object { $_.ConvertToDateTime($_.LastBootUpTime) }
Note: The extra properties you saw, added by a remote Invoke-Command call with a -ComputerName argument (described below), are still technically present on the result, but they won't display.
That said, the WMI cmdlets were deprecated in PowerShell version 3. Using Get-CimInstance in lieu of Get-WmiObject actually makes the .ConvertToDateTime() call unnecessary (the .LastBootUpTime now directly contains a [datetime] instance), in which case you can simply use Select-Object's -ExpandProperty parameter in order to return the property value only (rather than a [pscustomobject] instance with the requested property):
Get-CimInstance CIM_OperatingSystem | Select-Object -ExpandProperty LastBootUpTime
Note: Get-CimInstance directly supports a -ComputerName argument, so you don't need Invoke-Command -ComputerName for the invocation; unlike the firewall-unfriendly DCOM protocol that the WMI cmdlets use, the CIM cmdlets use the same, firewall-friendly transport as PowerShell remoting.
Or, more succinctly and efficiently, especially in a case such as this where the command returns only a single object, use direct property access:
(Get-CimInstance CIM_OperatingSystem).LastBootUpTime
This answer contrasts the pros and cons of these two approaches and shows other alternatives.
As for what you tried, which generally relates to:
Managing the origin properties automatically added by remote operations:
In remoting scenarios, PowerShell decorates the objects returned with additional properties that provide origin information. These properties are (mostly) of type NoteProperty and are added:
when PowerShell remoting is involved - such as via Invoke-Command -ComputerName in your case.
when CIM cmdlets such as Get-CimInstance are directly used remotely, such as with the -ComputerName parameter.
These properties are:
.PSComputerName (the name of the remote computer on which the code was executed)
Note: On objects returned from remote CIM calls, .PSComputerName appears as a regular property (type Property), not a NoteProperty.
The associated hidden .PSShowComputerName property, which defaults to $true, which explains why you saw a PSComputerName column in the display output.
If you capture the objects before printing them to the screen, you can set the property to $false on them, in which case their .PSComputerName property won't show (but will still be there) - however, the .RunspaceId property may - situationally - still show, and would have to be explicitly excluded - see below.
PowerShell remoting only (not remote CIM calls): .RunspaceId (the ID of the remote runspace)
To exclude these from local display / presence on the object, use the following techniques:
If you're only interested in select properties, make the Select-Object call locally, which, by virtue of locally constructing new [pscustomobject] instances with the properties of interest only, implicitly excludes the remoting-added properties:
Invoke-Command -ComputerName ... { ... } |
Select-Object Name, LastBootUpTime # LOCAL call to Select-Object
If you're interested in all properties except the remoting-added ones, use Select-Object -ExcludeProperty to eliminate them explicitly:
# Get remote output, then locally exclude the remoting-added properties.
Invoke-Command -ComputerName ... { ... } |
Select-Object * -ExcludeProperty PSComputerName, PSShowComputerName, RunSpaceId
Note: Select-Object generally returns [pscustomobject] instances whose properties are static copies of the input objects and which lack the input type's methods.
I found one way! if someone to need here is:
Get-WmiObject win32_operatingsystem | select #{LABEL=’LastBootUpTime’;EXPRESSION={$_.ConverttoDateTime($_.lastbootuptime)}}|Select-Object -ExpandProperty lastbootuptime
Here is how I used (I'm creating a report in HTML for my database)
write-output "<p> Horario do Ultimo boot: $(Get-WmiObject win32_operatingsystem | select #{LABEL=’LastBootUpTime’;EXPRESSION={$_.ConverttoDateTime($_.lastbootuptime)}}|Select-Object -ExpandProperty lastbootuptime)</p>"
The output was (in my language and region):
Horario do Ultimo boot: 09/14/2019 10:41:50

Detection script for windows hotfixes

So we have recently had issues with the KB971033 update within our network and i have managed to get a working script for removing it and reactivating windows, however when trying to get a detection script working to assure it only runs on effected computers i cant get it to correctly output true or false when testing against installed KBs.
So far this is what im running. No matter what i do it will output false. Anything obvious i am missing?
if ((get-hotfix).hotfixid -eq "KB971033") {$true} else {$false}
(get-hotfix).hotfixid returns an array, so you should not compare that with -eq.
This ought to do it:
((Get-HotFix | Select-Object -ExpandProperty HotFixID) -contains 'KB971033')
or for short:
(((Get-HotFix).HotFixID) -contains 'KB971033')
It's IMO quite inefficient to sieve through all Hotfixes when testing a distinct one.
if (Get-Hotfix -ID KB971033 -EA 0) {$true} else {$false}
-EA 0 is an abbreviation for -ErrorAction SilentlyContinue
Maybe Try
if ($(get-hotfix).hotfixid -eq "KB971033") {$true} else {$false}
The "$" is going to make "Get-Hotfix" result into an object with member ".hotfixID".
In my Windows Server 2016 Environment your Code works fine...maybe the Hotfix is not installed or not listed with 'get-hotfix'
Otherwise you can try this:
$HotfixID= "KB971033"
IF((get-hotfix).hotfixid | ?{ $_ -eq $HotfixID}){$true} else {$false}
It works also on Remote Computer:
(get-hotfix).hotfixid -ComputerName "***SomeDNSName / FQDN***"

Why am I getting no output when I try to search for a deleted user in Active Directory through PowerShell?

I am trying to search Active Directory for deleted users with PowerShell, but am unable to return any results even though I have used the -IncludeDeletedObjects parameter. Here is the command that I used:
get-adobject -filter{Name -like "$user"} -includedeletedobjects -properties *
The answer that worked for me is the command below will list all the users that were deleted from the Active Directory if your AD recycle bin is enabled and if you have sufficient privileges on Active Directory
Get-AdObject -Filter 'ObjectClass -eq "user" -and IsDeleted -eq $True' -IncludeDeletedObjects -Properties * | Ft Name,IsDeleted,WhenCreated
If you don't have the AD Recycle Bin enabled, you won't be able to find deleted objects.
If $user is expected to an exact match, you should also be using the -eq operator, not -like. If you want a fuzzy match, -like is correct but you should surround $user with * like so: *${user}*.
If $user is supposed to be the logon name, and not the friendly name of the user, then Name isn't the correct property to filter on, you will want to check against SamAccountName, not Name:
Get-ADObject -Filter "SamAccountName -eq '$user'"
If you are only interested in user objects, and not other AD object types, consider usingGet-ADUser in lieu of Get-ADObject. The syntax for what you specified above is the same, but will guarantee you only get ADUser objects, not ADComputer, ADGroup, etc.
Also, you should avoid using -Properties * and -Filter { ScriptBlock } arguments when using the AD cmdlets. Only use the Properties you need to process later, and use a string based filter like so:
Get-ADObject -Filter "Name -like '*$user*'"
See my answer here for best practices when using the -Filter parameter with AD cmdlets (also explains why not to use -Properties *), and this answer here for more details on why you should not use ScriptBlock parameters for AD filters.

Is there a way to check AD group membership for a computer?

I am trying to check computer group membership through Powershell. I want to be able to specify a certain computer name and find which groups that computer is in but from a Powershell script. I am planning on running the script on a computer, grabbing the hostname, and then printing out what AD groups that computer is in. Is there an easy way to do this?
EDIT:
So the plan here is to have a computer check to see what groups it is in, then assign a printer based on which group it is in. We have many printers that only 3 to 4 people use but due to the spread out nature of the users cannot downsize the amount of printers. I was looking at group policy but did not want to create 20 different GPOs. I wanted to do this with a logon/startup script. I'm not sure if this is doable or feasible.
Edit #2:
This edit it really late to the party but I figured if anyone found this it could help. We ended up using item level targeting on User>Preferences>Control Panel>Printers objects. We made an account in AD for each group of users needing access to the printers. This worked although it did create a long logon process for the first logon of the computer. We also enabled Point-to-Print restrictions so the drivers were loaded from the servers quietly.
This will give you the group membership (group names) of the local computer (requires powershell 2.0):
([adsisearcher]"(&(objectCategory=computer)(cn=$env:COMPUTERNAME))").FindOne().Properties.memberof -replace '^CN=([^,]+).+$','$1'
Apologies if I'm a bit late to the party on this but I needed to find a computer's group membership as well. After a lot of trial and error, this worked for me.
Get-ADComputer "mycomp" -Properties MemberOf | %{if ($_.MemberOf -like "*group name*") {Write-Host "found"} }
I noticed that if the string comparison is on a separate line, I needed to do the following
$g=Get-ADGroupMember -Identity "CN=myADgroup,OU=myOU,DC=corp,DC=com" -server corp.com
foreach($mbr in $g) {if($name.MemberOf -like "*mycomp*" -eq $true) {Write-Host "found"}}
Not sure but I imagine that testing the computer might be faster and easier than testing the group depending on the number of members.
the gpresult method seems to be the only way I can find that is accurate. Querying AD is not accurate since the computer may have been added to groups but not rebooted. I am sure someone could condense this but it worked well enough for what I needed to see.
# Get all active domain servers
$staledate = (Get-Date).AddDays(-90)
$computers = Get-ADComputer -Filter {(OperatingSystem -Like "*Server*") -and (Enabled -eq $True) -and (LastLogonDate -ge $staledate) -and (Modified -ge $staledate) -and (PasswordLastSet -ge $staledate) -and (whenChanged -ge $staledate) -and (Name -notlike "PHXVSSA101A")} | Select name -expandproperty name
$computers = $computers | Where {(Resolve-DNSName $_.name -ea 0) -and (Test-Connection -ComputerName $_.Name -Count 1 -ea 0)} | Sort
# Loop through all active domain servers
Foreach ($computer in $computers)
{
# Pull the gpresult for the current server
$Lines = gpresult /s $computer /v /SCOPE COMPUTER
# Initialize arrays
$cgroups = #()
$dgroups = #()
# Out equals false by default
$Out = $False
# Define start and end lines for the section we want
$start = "The computer is a part of the following security groups"
$end = "Resultant Set Of Policies for Computer"
# Loop through the gpresult output looking for the computer security group section
ForEach ($Line In $Lines)
{
If ($Line -match $start) {$Out = $True}
If ($Out -eq $True) {$cgroups += $Line}
If ($Line -match $end) {Break}
}
# Loop through all the gathered groups and check for Active Directory groups
ForEach ($group in $cgroups)
{
Try {
$check = Get-ADgroup $group -ErrorAction Stop
If ($check) {
$dgroups += $group
}
}
Catch {}
}
# Output server name and any Active Directory groups it is in
$computer
$dgroups
# End of computers loop
}
try running gpresult /V and check under "security GROUPS"
You can also try gpresult /scope computer /v under a command prompt (elevated to admin) for more specific results
Heres an LDAP query to find if a computer is in a group recursively:
(((objectClass=computer)(sAMAccountName=COMPUTERNAME$))(memberof:1.2.840.113556.1.4.1941:=DistinguishedNameOfGroup))
More info: http://justanotheritblog.co.uk/2016/01/27/recursively-check-if-a-usercomputer-is-a-member-of-an-ad-group-with-powershell-2-0/
To check the computer's own view of group membership, you can run:
(New-Object System.Security.Principal.WindowsPrincipal("$env:computername$")).IsInRole('Example Group')
True
Taking the computer out of Example Group doesn't affect the output of the above until the computer is rebooted.
Try this DOS Command, this will return all the local groups this computer belong to :
net localgroup

Resources