How to parse all given arguments in PowerShell - powershell

I want to create a loop function that looks like this:
function Loop { foreach ($File in Get-ChildItem | Select-Object -exp Name) { # Some command } }
It works perfectly fine for simple one-word commands, but it doesn't work for anything else. Of course, I need a way to parse all given arguments, but I don't know how. All documentations that I've been able to understand (I just started working with PowerShell about a week ago) don't seem to have an answer to this.
It would be great if someone could give me a solution to this problem.🙂

Like issuing several commands inside the loop?
#!/usr/bin/env powershell
function script:Loop {
foreach ($File in Get-ChildItem | Select-Object -ExpandProperty Name) {
##Some command
##another command
## a test
Write-Output -InputObject ('The current item is named {0}.' -f $file)
}
}
Loop
output
PS C:\Powershell\Scripts> . "c:\Powershell\Scripts\forloop.ps1"
The current item is named dchero.ps1.
The current item is named findinstaller.ps1.
The current item is named Untitled11.ps1.
The current item is named Untitled5.ps1.
The current item is named Untitled8.ps1.
However you don't really need to do the Select-Object -ExpandProperty Name because Get-ChildItem returns multiple properties for the objects it finds. You can see all of them by piping into Get-Member
PS C:\Powershell\Scripts> Get-ChildItem | Get-Member
TypeName: System.IO.FileInfo
Name MemberType Definition
---- ---------- ----------
Target AliasProperty Target = LinkTarget
LinkType CodeProperty System.String LinkType{get=GetLinkType;}
Mode CodeProperty System.String Mode{get=Mode;}
ModeWithoutHardLink CodeProperty System.String ModeWithoutHardLink{get=ModeWithoutHardLink;}
AppendText Method System.IO.StreamWriter AppendText()
CopyTo Method System.IO.FileInfo CopyTo(string destFileName), System.IO.FileInfo CopyTo(string destFileName, bool overwrite)
Create Method System.IO.FileStream Create()
CreateAsSymbolicLink Method void CreateAsSymbolicLink(string pathToTarget)
CreateText Method System.IO.StreamWriter CreateText()
Decrypt Method void Decrypt()
Delete Method void Delete()
Encrypt Method void Encrypt()
Equals Method bool Equals(System.Object obj)
GetHashCode Method int GetHashCode()
GetLifetimeService Method System.Object GetLifetimeService()
GetObjectData Method void GetObjectData(System.Runtime.Serialization.SerializationInfo info, System.Runtime.Serialization.StreamingContext context), void ISerializab…
GetType Method type GetType()
InitializeLifetimeService Method System.Object InitializeLifetimeService()
MoveTo Method void MoveTo(string destFileName), void MoveTo(string destFileName, bool overwrite)
Open Method System.IO.FileStream Open(System.IO.FileMode mode), System.IO.FileStream Open(System.IO.FileMode mode, System.IO.FileAccess access), System.IO.F…
OpenRead Method System.IO.FileStream OpenRead()
OpenText Method System.IO.StreamReader OpenText()
OpenWrite Method System.IO.FileStream OpenWrite()
Refresh Method void Refresh()
Replace Method System.IO.FileInfo Replace(string destinationFileName, string destinationBackupFileName), System.IO.FileInfo Replace(string destinationFileName,…
ResolveLinkTarget Method System.IO.FileSystemInfo ResolveLinkTarget(bool returnFinalTarget)
ToString Method string ToString()
PSChildName NoteProperty string PSChildName=dchero.ps1
PSDrive NoteProperty PSDriveInfo PSDrive=C
PSIsContainer NoteProperty bool PSIsContainer=False
PSParentPath NoteProperty string PSParentPath=Microsoft.PowerShell.Core\FileSystem::C:\Powershell\Scripts
PSPath NoteProperty string PSPath=Microsoft.PowerShell.Core\FileSystem::C:\Powershell\Scripts\dchero.ps1
PSProvider NoteProperty ProviderInfo PSProvider=Microsoft.PowerShell.Core\FileSystem
Attributes Property System.IO.FileAttributes Attributes {get;set;}
CreationTime Property datetime CreationTime {get;set;}
CreationTimeUtc Property datetime CreationTimeUtc {get;set;}
Directory Property System.IO.DirectoryInfo Directory {get;}
DirectoryName Property string DirectoryName {get;}
Exists Property bool Exists {get;}
Extension Property string Extension {get;}
FullName Property string FullName {get;}
IsReadOnly Property bool IsReadOnly {get;set;}
LastAccessTime Property datetime LastAccessTime {get;set;}
LastAccessTimeUtc Property datetime LastAccessTimeUtc {get;set;}
LastWriteTime Property datetime LastWriteTime {get;set;}
LastWriteTimeUtc Property datetime LastWriteTimeUtc {get;set;}
Length Property long Length {get;}
LinkTarget Property string LinkTarget {get;}
Name Property string Name {get;}
BaseName ScriptProperty System.Object BaseName {get=if ($this.Extension.Length -gt 0){$this.Name.Remove($this.Name.Length - $this.Extension.Length)}else{$this.Name};}
VersionInfo ScriptProperty System.Object VersionInfo {get=[System.Diagnostics.FileVersionInfo]::GetVersionInfo($this.FullName);}
Now that we know what's available we can use them for our scripts.
Like so:
#!/usr/bin/env powershell
function script:Loop {
foreach ($File in (Get-ChildItem)) {
##Some command
##another command
## a test
Write-Output -InputObject ('The current item is named {0}.' -f $file.Name)
Write-Output -InputObject ('The current items size it {0}.' -f $file.Length)
Write-Output -InputObject ('The current items hashcode is {0}.
' -f $file.GetHashCode())
}
}
Loop
Output
PS C:\Powershell\Scripts> . "c:\Powershell\Scripts\forloop.ps1"
The current item is named dchero.ps1.
The current items size it 755.
The current items hashcode is 31624384.
The current item is named findinstaller.ps1.
The current items size it 236.
The current items hashcode is 55386574.
The current item is named forloop.ps1.
The current items size it 466.
The current items hashcode is 50677768.
Finally you can get fancy and make changes to the objects or test them.
#!/usr/bin/env powershell
function script:Loop {
foreach ($File in (Get-ChildItem)) {
## command /argument 1
if ($file.Name -like "*.ps1") {
<# Action to perform if the condition is true #>
Write-Output "We've got a Powershell script here!"
Write-Output "The script is named $file.name"
}
else {
Write-Output "This ain't a Powershell script."
Write-Output "It's named $file.name"
}
## command / arugment 2
$newname = $file.BaseName + "-modifiedbyscript" + $file.Extension
Rename-Item -Path $file.FullName -NewName $newname -WhatIf
}
}
Loop

This might be a hard guess, if it has nothing to do with what you're looking for let me know and I'll delete this answer. If it has something to do with what you're looking I can understand why it could be "hard to explain".
function ThisThing {
[CmdletBinding()]
param(
[parameter(Mandatory, ParameterSetName = 'Expression')]
[scriptblock] $Expression,
[parameter(Mandatory, ParameterSetName = 'Condition')]
[scriptblock] $Condition,
[parameter(Mandatory, ValueFromPipeline, Position = 0)]
[object[]] $InputObject
)
process {
if($PSCmdlet.ParameterSetName -eq 'Expression') {
if($MyInvocation.ExpectingInput) {
return & $Expression
}
$InputObject | & {
process {
& $Expression
}
}
}
else {
if($MyInvocation.ExpectingInput) {
return & { if(& $Condition) { $_ } }
}
$InputObject | & {
process {
if(& $Condition) { $_ }
}
}
}
}
}
A few examples to test the function:
ThisThing (0..10) -Expression {
[pscustomobject]#{
Input = $_
}
}
Get-ChildItem | ThisThing -Expression {
if($_.CreationTime -lt (Get-Date).AddDays(-30)) {
[pscustomobject]#{
CreationDate = $_.CreationTime
Path = $_.FullName
}
}
}
Get-Process | ThisThing -Condition { $_.Name -eq 'svchost' }
ThisThing (Get-Service) -Condition { $_.Status -eq 'Stopped' }

Related

Cannot pipe to Get-Content from binary module using FileInfo

I am having a hard time piping a file to Get-Content (version PS 5.1).
Module code:
[Cmdlet(VerbsDiagnostic.Test, "FilePiping")]
public class PSTestFilePiping : PSCmdlet
{
[Parameter(Position = 0, Mandatory = true)]
public string FileName { get; set; }
protected override void ProcessRecord()
{
WriteObject(new System.IO.FileInfo(FileName));
}
}
Commands:
$x = Test-FilePiping .\readme.txt
$y = gci .\readme.txt
(I am using a relative path for simplicity)
Both $x and $y are a FileInfo object according to GetType():
IsPublic IsSerial Name BaseType
True True FileInfo System.IO.FileSystemInfo
Yet I cannot do:
$x | gc
The input object cannot be bound to any parameters for the command either because the command does not take pipeline input or the input and its properties do not match any of the parameters that take pipeline input.
but I can do:
$y | gc
This has me flummoxed.
Where did I go wrong?
In addition to #santiago-squarzon's helpful answer, there are two things worth noting here:
PowerShell commands like Get-Item and Get-ChildItem are not just made for the FileSystem so return information for the relevant provider, which is where values like PSPath come from.
Targeting a relative path with new FileInfo() will probably not find the file you are expecting, so we should get the full path just in case.
This can be achieved in your cmdlet so that it returns the PSPath property necessary for Get-Content.
Sample:
dotnet new classlib -o PSSample -n PSSample
cd PSSample
dotnet add package PowerShellStandard.Library --version 5.1.0
code . # I am using VSC - open your editor in the directory.
# Set target framework to netstandard2.0 in .csproj
# Copy and paste below in to Class1.cs
dotnet restore
dotnet build
ipmo .\bin\Debug\netstandard2.0\PSSample.dll
Test-FilePiping -FileName .\Class1.cs | FL *
Test-FilePiping -FileName .\Class1.cs | Get-Content
Cmdlet class:
using System;
using System.IO;
using System.Linq;
using System.Management.Automation;
namespace PSSample
{
[Cmdlet(VerbsDiagnostic.Test, "FilePiping")]
public class PSTestFilePiping : PSCmdlet
{
[Parameter(Position = 0, Mandatory = true)]
public string FileName { get; set; }
protected override void ProcessRecord()
{
string filePath = GetRelativePath(FileName);
var item = InvokeProvider.Item.Get(filePath);
WriteObject(item, true); // true enumerates the collection, because InvokeProvider.Item.Get() returns a collection.
}
protected string GetRelativePath(string path)
{
string currentDir = GetVariableValue("PWD").ToString();
if (Path.IsPathRooted(path) == true || path.StartsWith("\\", StringComparison.CurrentCulture))
{
// Nothing to see here.
}
else
{
if (path == ".")
{
path = currentDir;
}
else if (path.StartsWith("..", StringComparison.CurrentCulture))
{
path = Path.Combine(
string.Join("\\",
currentDir.Split('\\').Take(currentDir.Split('\\').Count() - path.Split('\\').Count(p => p == "..")).ToArray()
),
string.Join("\\", path.Split('\\').Where(f => f != "..").ToArray()));
}
else if (path.StartsWith(".", StringComparison.CurrentCulture))
{
path = Path.Combine(currentDir, path.Substring(2));
}
else
{
path = Path.Combine(currentDir, path);
}
}
return path;
}
}
}
Output:
PS C:\Code\PSSample> Test-FilePiping -FileName .\Class1.cs | FL *
PSPath : Microsoft.PowerShell.Core\FileSystem::C:\Code\PSSample\Class1.cs
PSParentPath : Microsoft.PowerShell.Core\FileSystem::C:\Code\PSSample
PSChildName : Class1.cs
PSDrive : C
PSProvider : Microsoft.PowerShell.Core\FileSystem
PSIsContainer : False
Mode : -a----
VersionInfo : File: C:\Code\PSSample\Class1.cs
InternalName:
OriginalFilename:
FileVersion:
FileDescription:
Product:
ProductVersion:
Debug: False
Patched: False
PreRelease: False
PrivateBuild: False
SpecialBuild: False
Language:
BaseName : Class1
Target : {}
LinkType :
Name : Class1.cs
Length : 1947
DirectoryName : C:\Code\PSSample
Directory : C:\Code\PSSample
IsReadOnly : False
Exists : True
FullName : C:\Code\PSSample\Class1.cs
Extension : .cs
CreationTime : 02/05/2021 13:03:22
CreationTimeUtc : 02/05/2021 12:03:22
LastAccessTime : 02/05/2021 13:04:13
LastAccessTimeUtc : 02/05/2021 12:04:13
LastWriteTime : 02/05/2021 13:04:00
LastWriteTimeUtc : 02/05/2021 12:04:00
Attributes : Archive
PS C:\Code\PSSample> Test-FilePiping -FileName .\Class1.cs | Get-Content
using System;
using System.IO;
using System.Linq;
using System.Management.Automation;
namespace PSSample
{
[Cmdlet(VerbsDiagnostic.Test, "FilePiping")]
public class PSTestFilePiping : PSCmdlet
{
[Parameter(Position = 0, Mandatory = true)]
public string FileName { get; set; }
protected override void ProcessRecord()
{
string filePath = GetRelativePath(FileName);
var item = InvokeProvider.Item.Get(filePath);
WriteObject(item, true); // true enumerates the collection, because InvokeProvider.Item.Get() returns a collection.
}
protected string GetRelativePath(string path)
{
string currentDir = GetVariableValue("PWD").ToString();
if (Path.IsPathRooted(path) == true || path.StartsWith("\\", StringComparison.CurrentCulture))
{
// Nothing to see here.
}
else
{
if (path == ".")
{
path = currentDir;
}
else if (path.StartsWith("..", StringComparison.CurrentCulture))
{
path = Path.Combine(
string.Join("\\",
currentDir.Split('\\').Take(currentDir.Split('\\').Count() - path.Split('\\').Count(p => p == "..")).ToArray()
),
string.Join("\\", path.Split('\\').Where(f => f != "..").ToArray()));
}
else if (path.StartsWith(".", StringComparison.CurrentCulture))
{
path = Path.Combine(currentDir, path.Substring(2));
}
else
{
path = Path.Combine(currentDir, path);
}
}
return path;
}
}
}
To complement the existing, helpful answers with some background information:
It is the PowerShell FileSystem provider that decorates the System.IO.FileSystemInfo instances (both System.IO.FileInfo and System.IO.DirectoryInfo) that Get-ChildItem and Get-Item emit with additional properties such as PSPath (among several others [1]), using PowerShell's ETS (Extended Type System).
The .PSPath property values of pipeline input objects are what bind to the -LiteralPath parameter of cmdlets such as Get-Content, due to said parameter being declared with the ValueFromPipelineByPropertyName property and LiteralPath being decorated with an [Alias("PSPath")] attribute; that is, PSPath is an alias (another name for) LiteralPath.
As of this writing, the PowerShell providers add these ETS properties as instance properties, which is the reason that a directly constructed System.IO.FileInfo does not have these properties, resulting in the symptom you saw (the absence of the .PSPath property prevented binding to the -LiteralPath parameter).
If the providers were to use type-level ETS properties (associated with the .NET type itself rather than with specific instances of it), this problem would go away, as such properties would then surface irrespective of how an instance was constructed.
See GitHub issue #4347 for a discussion.
[1] The full list of added properties is: PSPath, PSParentPath, PSChildName, PSDrive, PSProvider, PSIsContainer,
Mode, BaseName, Target, LinkType.
Hopefully this helps you identify your error:
PS /> 'Hello world!' > test.txt
PS /> $reader = [System.IO.FileInfo]::new('test.txt')
If I try to pipe this object directly to Get-Content it will throw with the same error you're getting:
Using this:
PS /> $reader | Get-Content
Or this:
PS /> $reader.FullName | Get-Content
Results in:
Get-Content: The input object cannot be bound to any parameters for the command either because the command does not take pipeline input or the input and its properties do not match any of the parameters that take pipeline input.
This is because none of the properties returned by [System.IO.FileInfo] matches those paremeters accepted as ValueFromPipelineByProperyName by Get-Content:
PS /> $reader | gm -MemberType Property
TypeName: System.IO.FileInfo
Name MemberType Definition
---- ---------- ----------
Attributes Property System.IO.FileAttributes Attributes {get;set;}
CreationTime Property datetime CreationTime {get;set;}
CreationTimeUtc Property datetime CreationTimeUtc {get;set;}
Directory Property System.IO.DirectoryInfo Directory {get;}
DirectoryName Property string DirectoryName {get;}
Exists Property bool Exists {get;}
Extension Property string Extension {get;}
FullName Property string FullName {get;}
IsReadOnly Property bool IsReadOnly {get;set;}
LastAccessTime Property datetime LastAccessTime {get;set;}
LastAccessTimeUtc Property datetime LastAccessTimeUtc {get;set;}
LastWriteTime Property datetime LastWriteTime {get;set;}
LastWriteTimeUtc Property datetime LastWriteTimeUtc {get;set;}
Length Property long Length {get;}
Name Property string Name {get;}
However if we create an object with any of the properties I mentioned in my comment, Get-Content will accept it as input and read it without any problems:
PS /> [PSCustomObject]#{ Path = $reader.FullName } | Get-Content
Hello world!
PS /> [PSCustomObject]#{ LiteralPath = $reader.FullName } | Get-Content
Hello world!
PS /> [PSCustomObject]#{ PSPath = $reader.FullName } | Get-Content
Hello world!
Get-ChildItem works fine because the object returned has the PSPath property.
The best way to identify which parameters are accepted as ValueFromPipelineByProperyName is to rely on MS Docs:
-LiteralPath
Type
String[]
Aliases
PSPath, LP
Position
Named
Default value
None
Accept pipeline input
True
Accept wildcard characters
False

Powershell Get-EventLog find event with the matching string in its message

I need to look through eventLog security ID 4648, and find the last time the user connected to the machine.
Currently this is my code:
$Values = invoke-command -ComputerName $ComputerName {Get-EventLog -LogName Security -InstanceID 4648 | Select-Object -ExpandProperty Message| ForEach-Object {if($_.Log -match "$String2"){
$_
Break }}}
$Values
The aim was to go through each log until a log where the message has the previously defined username is found, and then stop going through EventLog and return that log.
This is working well, except its not matching the correct log with the specified string.
Is there a way to improve how the matching works? So it actually finds the correct log with the specified user?
# Fill in the regex for the userName
$userName = "userName"
$Values = #(invoke-command -ComputerName $ComputerName {
Get-EventLog -LogName Security -InstanceID 4648 | Where-Object { $_.message -match $Using:userName } | Select-Object -First 1)
}
Your above sample won't work since message is of type string, therefore it doesn't have a Log property. Since we want $userName to be avaiable for read access on the remote machine we can use the $Using: syntax. To break the pipeline "iteration" I'm using Select-Object -First 1 which will return the first object passing the Where-Objectclause.
Resulting from that $Values points to a collection of (deserialized) objects (using the #() operator) of type:
TypeName: System.Diagnostics.EventLogEntry#Security/Microsoft-Windows-Security-Auditing/4648
Which means you can change the -First parameter to e.g. 10 and sort the result on the client machine:
$Values | sort TimeGenerated -Descending
If you want to know which properties are available you can use:
> $Values | gm
TypeName: System.Diagnostics.EventLogEntry#Security/Microsoft-Windows-Security-Auditing/4648
Name MemberType Definition
---- ---------- ----------
Disposed Event System.EventHandler Disposed(System.Object, System.EventArgs)
CreateObjRef Method System.Runtime.Remoting.ObjRef CreateObjRef(type requestedType)
Dispose Method void Dispose(), void IDisposable.Dispose()
Equals Method bool Equals(System.Diagnostics.EventLogEntry otherEntry), bool Equals(System.Object obj)
GetHashCode Method int GetHashCode()
GetLifetimeService Method System.Object GetLifetimeService()
GetObjectData Method void ISerializable.GetObjectData(System.Runtime.Serialization.SerializationInfo info, System.Runtime.Serialization.StreamingContext context)
GetType Method type GetType()
InitializeLifetimeService Method System.Object InitializeLifetimeService()
ToString Method string ToString()
Category Property string Category {get;}
CategoryNumber Property int16 CategoryNumber {get;}
Container Property System.ComponentModel.IContainer Container {get;}
Data Property byte[] Data {get;}
EntryType Property System.Diagnostics.EventLogEntryType EntryType {get;}
Index Property int Index {get;}
InstanceId Property long InstanceId {get;}
MachineName Property string MachineName {get;}
Message Property string Message {get;}
ReplacementStrings Property string[] ReplacementStrings {get;}
Site Property System.ComponentModel.ISite Site {get;set;}
Source Property string Source {get;}
TimeGenerated Property datetime TimeGenerated {get;}
TimeWritten Property datetime TimeWritten {get;}
UserName Property string UserName {get;}
EventID ScriptProperty System.Object EventID {get=$this.get_EventID() -band 0xFFFF;}
Hope that helps.

Combining Get-ACL results into 1 object

Please excuse my beginner level powershell.
I want to be able to combine the results of different results of Get-ACL into one object that'll later be exported
At the very basic level all I want is to combine different results of different folders for code below:
$test = (get-acl $path).Access | select -ExpandProperty IdentityReference
This gives me a result of:
Value
-----
NT AUTHORITY\SYSTEM
BUILTIN\Administrators
Etc
Etc
I want an object that will be like some thing like this (plus more columns, about 4-5 total):
Folder1 Folder2
----- -------
NT AUTHORITY\SYSTEM NT AUTHORITY\SYSTEM
BUILTIN\Administrators BUILTIN\Administrators
Etc Etc
Etc Etc
I tried exploring building a custom object, but I couldn't find a way to list the objects values properly like my first results
$Custom = New-Object PSObject
$Custom | Add-Member -type NoteProperty -name Folder1 -value $test.value
Gives me:
Folder1
-------
{NT AUTHORITY\SYSTEM, BUILTIN\Administrators, etc, etc ...}
How can I handle this to give me a result like the first object and then in turn add more to the custom object?
Thanks in advance,
Lou
Based on your description, I think what you need is simply a collection of objects, i.e., $aclObjectList
This script captures a collection where each object is the type of object returned by get-acl. I do this just so I can show you the path property of each object to demonstrate that each object is for one of the three folders involved
Then, the script loops through the array of get-acl objects and outputs the path and IdentityReference of each
If you want to export a single object, then export $aclObjectList
cls
#define and declare an array. A System.Collections.ArrayList can be big and is fast
$aclObjectList = New-Object System.Collections.ArrayList
$aclObjectList.clear()
$path = "C:\Temp\topFolder\Folder 1"
$aclObject = (get-acl $path)
$aclObjectList.Add($aclObject) | Out-Null
$path = "C:\Temp\topFolder\Folder 2"
$aclObject = (get-acl $path)
$aclObjectList.Add($aclObject) | Out-Null
$path = "C:\Temp\topFolder\Folder 3"
$aclObject = (get-acl $path)
$aclObjectList.Add($aclObject) | Out-Null
foreach ($aclObject in $aclObjectList)
{
write-host ($aclObject.Path)
$aclAccessObject = $aclObject.Access | select -ExpandProperty IdentityReference
foreach ($aclAccessItem in $aclAccessObject)
{
write-host ("item=" + $aclAccessItem.Value)
}
write-host
}
Output is:
Microsoft.PowerShell.Core\FileSystem::C:\Temp\topFolder\Folder 1
item=BUILTIN\Administrators
item=NT AUTHORITY\SYSTEM
item=BUILTIN\Users
item=NT AUTHORITY\Authenticated Users
item=NT AUTHORITY\Authenticated Users
Microsoft.PowerShell.Core\FileSystem::C:\Temp\topFolder\Folder 2
item=BUILTIN\Administrators
item=NT AUTHORITY\SYSTEM
item=BUILTIN\Users
item=NT AUTHORITY\Authenticated Users
item=NT AUTHORITY\Authenticated Users
Microsoft.PowerShell.Core\FileSystem::C:\Temp\topFolder\Folder 3
item=BUILTIN\Administrators
item=NT AUTHORITY\SYSTEM
item=BUILTIN\Users
item=NT AUTHORITY\Authenticated Users
item=NT AUTHORITY\Authenticated Users
By the way, the datatype of the object returned by get-acl is a System.Security.AccessControl.DirectorySecurity. You can see this by, e.g., piping one of the $aclObject variables to Get-Member:
$aclObject | Get-Member
TypeName: System.Security.AccessControl.DirectorySecurity
Name MemberType Definition
---- ---------- ----------
Access CodeProperty System.Security.AccessControl.AuthorizationRuleCollection Access{get=GetAccess;}
CentralAccessPolicyId CodeProperty System.Security.Principal.SecurityIdentifier CentralAccessPolicyId{get=GetCentralAccessPolicyId;}
CentralAccessPolicyName CodeProperty System.String CentralAccessPolicyName{get=GetCentralAccessPolicyName;}
Group CodeProperty System.String Group{get=GetGroup;}
Owner CodeProperty System.String Owner{get=GetOwner;}
Path CodeProperty System.String Path{get=GetPath;}
Sddl CodeProperty System.String Sddl{get=GetSddl;}
AccessRuleFactory Method System.Security.AccessControl.AccessRule AccessRuleFactory(System.Security.Principal.IdentityReference identityReference, int accessMask, bool isInherited...
AddAccessRule Method void AddAccessRule(System.Security.AccessControl.FileSystemAccessRule rule)
AddAuditRule Method void AddAuditRule(System.Security.AccessControl.FileSystemAuditRule rule)
AuditRuleFactory Method System.Security.AccessControl.AuditRule AuditRuleFactory(System.Security.Principal.IdentityReference identityReference, int accessMask, bool isInherited, ...
Equals Method bool Equals(System.Object obj)
GetAccessRules Method System.Security.AccessControl.AuthorizationRuleCollection GetAccessRules(bool includeExplicit, bool includeInherited, type targetType)
GetAuditRules Method System.Security.AccessControl.AuthorizationRuleCollection GetAuditRules(bool includeExplicit, bool includeInherited, type targetType)
GetGroup Method System.Security.Principal.IdentityReference GetGroup(type targetType)
GetHashCode Method int GetHashCode()
GetOwner Method System.Security.Principal.IdentityReference GetOwner(type targetType)
GetSecurityDescriptorBinaryForm Method byte[] GetSecurityDescriptorBinaryForm()
GetSecurityDescriptorSddlForm Method string GetSecurityDescriptorSddlForm(System.Security.AccessControl.AccessControlSections includeSections)
GetType Method type GetType()
ModifyAccessRule Method bool ModifyAccessRule(System.Security.AccessControl.AccessControlModification modification, System.Security.AccessControl.AccessRule rule, [ref] bool modi...
ModifyAuditRule Method bool ModifyAuditRule(System.Security.AccessControl.AccessControlModification modification, System.Security.AccessControl.AuditRule rule, [ref] bool modified)
PurgeAccessRules Method void PurgeAccessRules(System.Security.Principal.IdentityReference identity)
PurgeAuditRules Method void PurgeAuditRules(System.Security.Principal.IdentityReference identity)
RemoveAccessRule Method bool RemoveAccessRule(System.Security.AccessControl.FileSystemAccessRule rule)
RemoveAccessRuleAll Method void RemoveAccessRuleAll(System.Security.AccessControl.FileSystemAccessRule rule)
RemoveAccessRuleSpecific Method void RemoveAccessRuleSpecific(System.Security.AccessControl.FileSystemAccessRule rule)
RemoveAuditRule Method bool RemoveAuditRule(System.Security.AccessControl.FileSystemAuditRule rule)
RemoveAuditRuleAll Method void RemoveAuditRuleAll(System.Security.AccessControl.FileSystemAuditRule rule)
RemoveAuditRuleSpecific Method void RemoveAuditRuleSpecific(System.Security.AccessControl.FileSystemAuditRule rule)
ResetAccessRule Method void ResetAccessRule(System.Security.AccessControl.FileSystemAccessRule rule)
SetAccessRule Method void SetAccessRule(System.Security.AccessControl.FileSystemAccessRule rule)
SetAccessRuleProtection Method void SetAccessRuleProtection(bool isProtected, bool preserveInheritance)
SetAuditRule Method void SetAuditRule(System.Security.AccessControl.FileSystemAuditRule rule)
SetAuditRuleProtection Method void SetAuditRuleProtection(bool isProtected, bool preserveInheritance)
SetGroup Method void SetGroup(System.Security.Principal.IdentityReference identity)
SetOwner Method void SetOwner(System.Security.Principal.IdentityReference identity)
SetSecurityDescriptorBinaryForm Method void SetSecurityDescriptorBinaryForm(byte[] binaryForm), void SetSecurityDescriptorBinaryForm(byte[] binaryForm, System.Security.AccessControl.AccessContr...
SetSecurityDescriptorSddlForm Method void SetSecurityDescriptorSddlForm(string sddlForm), void SetSecurityDescriptorSddlForm(string sddlForm, System.Security.AccessControl.AccessControlSectio...
ToString Method string ToString()
PSChildName NoteProperty string PSChildName=Folder 1
PSDrive NoteProperty PSDriveInfo PSDrive=C
PSParentPath NoteProperty string PSParentPath=Microsoft.PowerShell.Core\FileSystem::C:\Temp\topFolder
PSPath NoteProperty string PSPath=Microsoft.PowerShell.Core\FileSystem::C:\Temp\topFolder\Folder 1
PSProvider NoteProperty ProviderInfo PSProvider=Microsoft.PowerShell.Core\FileSystem
AccessRightType Property type AccessRightType {get;}
AccessRuleType Property type AccessRuleType {get;}
AreAccessRulesCanonical Property bool AreAccessRulesCanonical {get;}
AreAccessRulesProtected Property bool AreAccessRulesProtected {get;}
AreAuditRulesCanonical Property bool AreAuditRulesCanonical {get;}
AreAuditRulesProtected Property bool AreAuditRulesProtected {get;}
AuditRuleType Property type AuditRuleType {get;}
AccessToString ScriptProperty System.Object AccessToString {get=$toString = "";...
AuditToString ScriptProperty System.Object AuditToString {get=$toString = "";...

Select-Object -ExpandProperty vs. Get-ItemPropertyValue

Most likely there's something fundamental I don't understand about PowerShell. I really don't like when writing even medium sized pipes, where grabbing a property breaks the workflow by having to put parens around the statement up to that point, for eg.
(Get-ChildItem ~\.gitconfig).Length
This is tedious. Because Length looks very much like a property, one would think
Get-ChildItem ~\.gitconfig | Get-ItemPropertyValue -Name Length
would work. However, it does not. Taking a look at the interface of the System.IO.FileSystemInfo object returned by the File System PSDrive provider, one sees that it doesn't have a Length property. It does have a FullName property though, hence
Get-ChildItem ~\.gitconfig | Get-ItemPropertyValue -Name FullName
works as expected. To retrieve the size (Length) of a file using the pipe, one has to use Select-Object with the -ExpandProperty like
Get-ChildItem ~\.gitconfig | Select-Object -ExpandProperty Length
How does one know up front whether placing a . after an object and iterating through the results of tab completion, if the entry is an object or a property? It's very annoying that even common operations are confusing as hell, given for instance that reading environmental variables goes by
Get-Item -Path Env:\USERNAME
returns
Name Value
---- -----
USERNAME mnagy
If it's an item, Get-ItemProperty and Get-ItemPropertyValue must play a role here. Because of the Name:Value structure of the result, newcomers might be intrigued to obtain the actual value saying
Get-Item -Path Env:\USERNAME | Get-ItemPropertyValue
or actually reading how Get-ItemPropertyValue should be used modify the query to
Get-ItemPropertyValue -Path Env:\ -Name USERNAME
which in fact results in
Get-ItemPropertyValue : Cannot use interface. The IPropertyCmdletProvider interface is not supported by this provider.
At line:1 char:1
+ Get-ItemPropertyValue -Path Env:\ -Name USERNAME
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : NotImplemented: (:) [Get-ItemPropertyValue], PSNotSupportedException
+ FullyQualifiedErrorId : NotSupported,Microsoft.PowerShell.Commands.GetItemPropertyValueCommand
This entire construction seems utterly inconsistent to me and most vexing, but hopefully not by design, but because I look at it from the wrong angle.
To your first note: Length, for .hg directoy, worked form me just fine (giving you the number of files within):
Ps C:\> (Get-ChildItem .hg).Length
18
I tend to use get-member to check what is supported and what is not.
If I check it for my directory reports:
(Get-ChildItem reports) | gm
TypeName: System.IO.FileInfo
Name MemberType Definition
---- ---------- ----------
LinkType CodeProperty System.String LinkType{get=GetLinkType;}
Mode CodeProperty System.String Mode{get=Mode;}
Target CodeProperty System.Collections.Generic.IEnumerable`1[[System.String, mscorlib, Version=...
AppendText Method System.IO.StreamWriter AppendText()
CopyTo Method System.IO.FileInfo CopyTo(string destFileName), System.IO.FileInfo CopyTo(s...
Create Method System.IO.FileStream Create()
CreateObjRef Method System.Runtime.Remoting.ObjRef CreateObjRef(type requestedType)
CreateText Method System.IO.StreamWriter CreateText()
Decrypt Method void Decrypt()
Delete Method void Delete()
Encrypt Method void Encrypt()
Equals Method bool Equals(System.Object obj)
GetAccessControl Method System.Security.AccessControl.FileSecurity GetAccessControl(), System.Secur...
GetHashCode Method int GetHashCode()
GetLifetimeService Method System.Object GetLifetimeService()
GetObjectData Method void GetObjectData(System.Runtime.Serialization.SerializationInfo info, Sys...
GetType Method type GetType()
InitializeLifetimeService Method System.Object InitializeLifetimeService()
MoveTo Method void MoveTo(string destFileName)
Open Method System.IO.FileStream Open(System.IO.FileMode mode), System.IO.FileStream Op...
OpenRead Method System.IO.FileStream OpenRead()
OpenText Method System.IO.StreamReader OpenText()
OpenWrite Method System.IO.FileStream OpenWrite()
Refresh Method void Refresh()
Replace Method System.IO.FileInfo Replace(string destinationFileName, string destinationBa...
SetAccessControl Method void SetAccessControl(System.Security.AccessControl.FileSecurity fileSecurity)
ToString Method string ToString()
PSChildName NoteProperty string PSChildName=jv_libgdbs_tests-20180822-Test.xml
PSDrive NoteProperty PSDriveInfo PSDrive=C
PSIsContainer NoteProperty bool PSIsContainer=False
PSParentPath NoteProperty string PSParentPath=Microsoft.PowerShell.Core\FileSystem::C:\prg_sdk\stx8-j...
PSPath NoteProperty string PSPath=Microsoft.PowerShell.Core\FileSystem::C:\prg_sdk\stx8-jv_swin...
PSProvider NoteProperty ProviderInfo PSProvider=Microsoft.PowerShell.Core\FileSystem
Attributes Property System.IO.FileAttributes Attributes {get;set;}
CreationTime Property datetime CreationTime {get;set;}
CreationTimeUtc Property datetime CreationTimeUtc {get;set;}
Directory Property System.IO.DirectoryInfo Directory {get;}
DirectoryName Property string DirectoryName {get;}
Exists Property bool Exists {get;}
Extension Property string Extension {get;}
FullName Property string FullName {get;}
IsReadOnly Property bool IsReadOnly {get;set;}
LastAccessTime Property datetime LastAccessTime {get;set;}
LastAccessTimeUtc Property datetime LastAccessTimeUtc {get;set;}
LastWriteTime Property datetime LastWriteTime {get;set;}
LastWriteTimeUtc Property datetime LastWriteTimeUtc {get;set;}
Length Property long Length {get;}
Name Property string Name {get;}
BaseName ScriptProperty System.Object BaseName {get=if ($this.Extension.Length -gt 0){$this.Name.Re...
VersionInfo ScriptProperty System.Object VersionInfo {get=[System.Diagnostics.FileVersionInfo]::GetVer...
How does one know up front whether placing a . after an object and
iterating through the results of tab completion, if the entry is an
object or a property?
You check it with with Get-Member.
For the Get-Item -Path Env:\USERNAME you can again check:
PS C:\> Get-Item -Path Env:\USERNAME | gm
TypeName: System.Collections.DictionaryEntry
Name MemberType Definition
---- ---------- ----------
Name AliasProperty Name = Key
Equals Method bool Equals(System.Object obj)
GetHashCode Method int GetHashCode()
GetType Method type GetType()
ToString Method string ToString()
PSDrive NoteProperty PSDriveInfo PSDrive=Env
PSIsContainer NoteProperty bool PSIsContainer=False
PSPath NoteProperty string PSPath=Microsoft.PowerShell.Core\Environment::USERNAME
PSProvider NoteProperty ProviderInfo PSProvider=Microsoft.PowerShell.Core\Environment
Key Property System.Object Key {get;set;}
Value Property System.Object Value {get;set;}
Now check the USERNAME (you see the key you are asking and its value):
PS C:\> (Get-Item -Path Env:\USERNAME).key
USERNAME
PS C:\> (Get-Item -Path Env:\USERNAME).value # my login
gurun

How to compare Microsoft.Exchange.Common.ScheduleInterval with a datetime object?

I want find out if there is any Exchange database schedule running, or will run in the next few hours. However, I couldn't figure out how to compare the scheduleinterval object with a variable I created with get-date or (get-date).addhours(20)
The scheduleInterval I am looking at is
C:\>(get-mailboxdatabase | where {$_.name -like 'database'}).maintenanceschedule | Get-Member
TypeName: Microsoft.Exchange.Common.ScheduleInterval
Name MemberType Definition
---- ---------- ----------
CompareTo Method int CompareTo(System.Object value), int CompareTo(Microsoft.Exchange.Common.ScheduleInterval...
ConjointWith Method bool ConjointWith(Microsoft.Exchange.Common.ScheduleInterval other)
Contains Method bool Contains(Microsoft.Exchange.Common.WeekDayAndTime dt), bool Contains(System.DateTime dt...
Equals Method bool Equals(System.Object obj)
GetHashCode Method int GetHashCode()
GetType Method type GetType()
Overlaps Method bool Overlaps(Microsoft.Exchange.Common.ScheduleInterval other)
ToString Method string ToString()
EndDay Property System.DayOfWeek EndDay {get;}
EndHour Property System.Int32 EndHour {get;}
EndMinute Property System.Int32 EndMinute {get;}
EndTime Property Microsoft.Exchange.Common.WeekDayAndTime EndTime {get;}
Length Property System.TimeSpan Length {get;}
StartDay Property System.DayOfWeek StartDay {get;}
StartHour Property System.Int32 StartHour {get;}
StartMinute Property System.Int32 StartMinute {get;}
StartTime Property Microsoft.Exchange.Common.WeekDayAndTime StartTime {get;}
Any help is much appreciated.
Thanks
Here a way to test if a job is running at the Get-Date value.
Maybe the comparison can be done casting starttime/endtime properties to [datetime] but I can't test, I'm just supposing..
$a = (get-mailboxdatabase | where {$_.name -like 'database'}).maintenanceschedule
$b = Get-date # you can add days to check events in the future
if ( $a.startday, $a.endday -contains $b.dayofweek)
{
if ( $a.starthour -le $b.hour -and $a.endhour -ge $b.hour)
{
if ( $a.startminute -le $b.minute -and $a.endminute -ge $b.minute)
{
Write-Host "Jod scheduled is running at this time!"
}
}
}
I wrote the following codes to convert the Microsoft.Exchange.Common.ScheduleInterval into an array of datetime objects. Hope someone can improve my codes...
$schedules=(get-mailboxdatabase|where {$_.name -like "dbname"}).maintenanceschedule
$curdatetime = get-date
$dowhash = #{"Monday"=1;"Tuesday"=2;"Wednesday"=3;"Thursday"=4; `
"Friday"=5;"Saturday"=6;"Sunday"=7}
$todaydow = $dowhash.get_item([string]$curdatetime.dayofweek)
$coming = #()
foreach ($schedule in $schedules) {
$dow = $dowhash.get_item([string]$schedule.startday)
$start = $curdatetime.adddays((($dow+7-$todaydow) % 7))
$startstr = "{0:yyyyMMdd}{1:00}{2:00}" `
-f $start,$schedule.starthour,$schedule.startminute
$dow = $dowhash.get_item([string]$schedule.endday)
$end = $curdatetime.adddays((($dow+7-$todaydow) % 7))
$endstr = "{0:yyyyMMdd}{1:00}{2:00}" `
-f $end,$schedule.endhour,$schedule.endminute
$coming+=,([datetime]::ParseExact($startstr,"yyyyMMddHHmm",$null), `
[datetime]::ParseExact($endstr,"yyyyMMddHHmm",$null) )
}
Thanks