PowerShell to check for missing ShadowCopies - powershell

Trying to check for SMB shares (DC's and member servers) that are missing Shadow Copies. Can't get the PowerShell filter just right.
This is the closest I've come. I'm still getting SYSVOL shares in the list.
Get-SmbShare -Special $False | FL Name,Path,ShadowCopy | Where-Object {(-not $_.ShadowCopy) -and ($_.Path -notlike "*sysvol*")}
I'm expecting the output to be like:
Name : test
Path : C:\test
ShadowCopy : False

You should never use the formatting cmdlet's in the middle of a pipeline. By using fl, you are essentially creating an array of strings. The where clause operates on those strings.
Most likely, you meant to do something like this
Get-SmbShare |
Where-Object {!($_.ShadowCopy) -and ($_.Path -notlike '*sysvol*')} |
fl name, path, shadowcopy

Related

Question about pipeline variables and pipeline shortcut(s)?

In the creation of a script I'm writing, I ran across the use of what appears to be a pipeline shortcut that I have never seen before.
For example:
$acl | select -expandproperty Access | ? {$_.IdentityReference -eq "AD\$Group"}
can be shortened to
$acl.Access.Where({$_.IdentityReference -eq "AD\$Group"})
What is this? $acl.Access makes sense to me as it's just a property reference but I do not see any such .Where() method being available on this object. As such it seems .Where({}) is some sort of pipeline shortcut for " | Where-Object {}". Where can I find documentation for such a thing? Do others like this exist?
Second question. I have a need to add a calculated property to my results, and within the property expression I have to perform piping as well, so where I would typically just reference $_ from the parent pipeline, this is lost within the expression statement.
I can get around this by using -PipelineVariable up within the pipeline, but it seems this only works when used with cmdlets and is not available when starting a pipeline with a variable (which I do often). Is there a way around this?
This works:
$acl = Get-Acl -Path "AD:\$dn"
$acl | select -expandproperty access -PipelineVariable AccessRight | ? {$_.IdentityReference -eq "AD\$Group"} | select *, #{N='ObjectTypeName';E={($ADGuidMap.GetEnumerator() | ? {$_.Value -eq $AccessRight.ObjectType}).Name}}
I'd really like to be able to do this with the shortcut as anywhere I can shorten my oneliner I would like to do. Unfortunately the following will not work as I cannot use pipelinevariable at this location.
$acl.Access.Where({$_.IdentityReference -eq "AD\$Group"}) -PipeLineVariable AccessRight | select *, #{N='ObjectTypeName';E={($ADGuidMap.GetEnumerator() | ? {$_.Value -eq $AccessRight.ObjectType}).Name}}
It's always bugged me about not being able to use Pipeline variables outside of cmdlets so I finally figured I'd ask if there was some sort of way around that.
As for the first question:
The .Where() and .ForEach() methods are intrinsic members, i.e. members that PowerShell implicitly makes available on objects of any type.
While they function similarly to their cmdlet counterparts, Where-Object and ForEach-Object, there are important differences.
See this answer for more information.
As an aside: You could have simplified your command even when using the Where-Object cmdlet, namely with simplified syntax:
$acl.Access | Where-Object IdentityReference -eq "AD\$Group"
As for the second question:
Because the .Where() method isn't a cmdlet, you cannot use the common -PipelineVariable parameter with it.
Given that .Access typically returns multiple objects, using the pipeline with -PipelineVariable enables an elegant solution.
If you do want to avoid the pipeline (operator), you can combine the .Where() and .ForEach() methods as follows, with the help of an intermediate (regular) variable:
$acl.Access.
Where({ $_.IdentityReference -eq "AD\$Group" }).
ForEach({
$aclEntry = $_
Select-Object -InputObject $aclEntry -Property *,
#{
N = 'ObjectTypeName'
E = { ($ADGuidMap.GetEnumerator().Where({ $_.Value -eq $aclEntry.ObjectType })).Name }
}
})
Update:
As you've discovered yourself, if you stick with a pipeline, you can combine -PipeLineVariable with Write-Output in order to capture each element of an array / collection in a pipeline variable as it flows through the pipeline, for use a later script block, as the following (contrived) example shows:
$array = 0..3
Write-Output $array -Pipeline arrayElement |
Where-Object { 0 -eq $_ % 2 } | # filter out odd numbers
ForEach-Object { $_ + 1 } | # add 1
ForEach-Object { "pipeline variable / `$_: $arrayElement / $_" }
Output, which shows that each element of input array $array was individually captured in pipeline variable $arrayElement:
pipeline variable / $_: 0 / 1
pipeline variable / $_: 2 / 3

PowerShell filtering twice on the same property

I would like to filter the content of a variable by two criteria referring to the same property. I ran into some struggle finding the correct syntax.
It looks like this:
$g = $allsites | Where-Object {($_.Name -like "[g]*") -and ($_.Name -notlike "[GRP-]*)"}
What I'm trying to achieve:
Create the variable $g with the filtered content of the variable $allsites where the Site Name starts with with the letter "G" no matter the following letters. This result has to be filtered again. The content of the variable $g should contain site which are not named starting the expression "GRP-" only.
The construct [GRP-] describes a character set, so you're instructing PowerShell to test if the name doesn't start with either G, R, P or -. Since you've already ensured that all names start with g already, this won't match any of them.
Change the pattern to just GRP-*:
$g = $allsites | Where-Object {$_.Name -like "G*" -and $_.Name -notlike "GRP-*"}

Get AD user properties from Active Directory

I am trying to filter the values of a property in Active Directory.
I tried:
Get-ADUser -filter * -Properties physicalDeliveryOfficeName | Where-Object (($_.physicalDeliveryOfficeName -like "NICE")) | Select-Object physicalDeliveryOfficeName, name
Get-ADUser -filter * -Properties physicalDeliveryOfficeName | Select-Object physicalDeliveryOfficeName, name | Where-Object (($_.physicalDeliveryOfficeName -like "NICE"))
I did not get any errors, but no results either.
I searched all users with physicaldeliverofficename is (myvalue). I would like to display name and office.
You have a syntax problem:
The Where-Object's (positionally implied) -FilterScript parameter expects a script block argument - { ... } - not a parenthesized expression ((...)).[1]
Therefore:
# Note the { ... } around the expression passed to Where-Object
Get-ADUser -Filter * -Properties physicalDeliveryOfficeName |
Where-Object { $_.physicalDeliveryOfficeName -eq "NICE" } # | ...
Note: Since "NICE" is a literal string rather than a wildcard pattern, I've used the -eq instead of the -like operator. If you doe need to find "NICE" as a substring, use something like -like "*NICE*" or, for case-sensitive matching, -clike "*NICE*", as Mathias R. Jessen suggests.
Note that you may alternatively use simplified syntax, which obviates the need for a script block and allows use of individual parameters (also note the absence of $_., which is implied):
Get-ADUser -Filter * -Properties physicalDeliveryOfficeName |
Where-Object physicalDeliveryOfficeName -eq "NICE" # | ...
Taking a step back:
Santiago Squarzon suggests performing the filtering at the source, by using Get-ADUser's -Filter or -LDAPFilter parameter, which is much more efficient; e.g.:
Get-ADUser -Filter 'physicalDeliveryOfficeName -eq "NICE"'
As an aside: There are many examples out there that use script-block syntax with -Filter (-Filter { ... }), but the -Filter parameter accepts a string and that string, even though it supports PowerShell-like syntax, is interpreted by the AD provider, so it's better to pass a string to begin with - see this answer for more information.
[1] If you use (...), the expression's value gets bound to the -Property parameter instead, and is therefore interpreted as a property name whose value - assuming such a property even exists - is interpreted as a Boolean that determines whether the input object at hand should be filtered in or not. If the expression doesn't evaluate to the name of a property that exists on an input object, $false is implied, and the input object is filtered out. In your case, this predictably resulted in no objects being filtered in and therefore no output.
The Select-Object cmdlet is used to select only the columns you want from a larger object or list.
For instance:
C:\git\Core> gsv Spooler | fl
Name : Spooler
DisplayName : Print Spooler
Status : Running
DependentServices : {Fax}
ServicesDependedOn : {RPCSS, http}
CanPauseAndContinue : False
CanShutdown : False
CanStop : True
ServiceType : Win32OwnProcess, InteractiveProcess
Get-Service returns Service Objects which have a lot of properties. If I only want certain ones, I'd use it like so:
C:\git\Core> gsv Spooler | Select Name,Status
Name : Spooler
Status : Running
You're using the cmdlet and probably discarding the columns which have the values you need. Run your one-liner again and remove the Select-Object cmdlet to see all of the columns availble, till you find the one that pertains to the Office.

Can't figure out Powershell Where-Object. SSAS Cube Processed State via Powershell,

I've created a powershell script to list the Processed State of a number of SSAS Cubes.
I'm puzzled why the Where-Object only produces the correct results when I use -like. I can't seem to use -eq. Anyone got any ideas ?
I'm using the Where-Object to zero in on the production Database.
The code i'm using is this..
Import-Module SQLASCmdlets -DisableNameChecking
$SSASServer = New-Object Microsoft.AnalysisServices.Server
$instanceName = "SSASSVR01"
$SSASServer.connect($instanceName)
$ProdCubes = $SSASServer.Databases.Cubes
$ProdCubes | Select Parent , State , Name `
| Where-Object { $_.Parent -like "DWProd*" }
I'd expect that -eq would work, but it doesn't
I don't get any response if the last line is written as...
$ProdCubes | Select Parent , State , Name `
| Where-Object { $_.Parent -eq "DWProd" }
I suspect it's whitespace, but how do you filter out the whitespace in powershell.

Troubles with substring, trim, trimend

I'm trying to take an array of email addresses (in the form of username#company.com) which is generated from:
$users = get-MSOLUser -All | where {$_.isLicensed -eq "TRUE" -and $_.Licenses.AccountSKUID -eq "my_license"} | select userprincipalname
And get just the username from each. I start with username#company.com and want to end up with username. I have tried various ways using substring, Trim, TrimEnd, etc and can't get any of them working.
$username = $users | %{$_.substring(0,$users.length - 12)}
$users | %{$_.trimend("#company.com")}
$users | %{$_.trimend(12)}
All of the above give errors including the two below.
Method invocation failed because [Selected.Microsoft.Online.Administration.User] does not
contain a method named substring.
Method invocation failed because [Selected.Microsoft.Online.Administration.User] does not
contain a method named trimend.
What am I doing wrong with the syntax, or is there something else, like a module I haven't imported, or how my syntax is trying to work with an array?
This will return you a list of all usernames (without domain) that fulfills your conditions:
$users = Get-MSOLUser -All |
Where-Object {$_.isLicensed -eq "TRUE" -and $_.Licenses.AccountSKUID -eq "my_license"} |
ForEach-Object { $_.userprincipalname -replace '#.*' }
Well, you need to work with the property, not with the object, so you would probably want to do something like:
select -expandproperty userprincipalname
but that would create an array of userprincipalnames, so no other attributes.
When you run get-MSOLUser you get back an object, with a bunch of properties. When you do select -expandproperty you are getting back only certain property, but not an object itself. You are getting back a system.string object. And that object has all those methods you are trying to invoke.