Why does PowerShell output change after loading assembly? - powershell

I am getting some unusual output from New-Item in a script if I've first loaded an assembly with reflection. Why?
If I run
[System.Reflection.Assembly]::LoadWithPartialName("Microsoft.Web.Administration")
New-Item -Path "temp" -ItemType directory
I get the following odd output from New-Item:
PSPath : Microsoft.PowerShell.Core\FileSystem::C:\Users\swoogan\Desktop\temp
PSParentPath : Microsoft.PowerShell.Core\FileSystem::C:\Users\swoogan\Desktop
PSChildName : temp
PSDrive : C
PSProvider : Microsoft.PowerShell.Core\FileSystem
PSIsContainer : True
Name : temp
Parent : Desktop
Exists : True
Root : C:\
FullName : C:\Users\swoogan\Desktop\temp
Extension :
CreationTime : 7/28/2014 11:03:10 AM
CreationTimeUtc : 7/28/2014 3:03:10 PM
LastAccessTime : 7/28/2014 11:03:10 AM
LastAccessTimeUtc : 7/28/2014 3:03:10 PM
LastWriteTime : 7/28/2014 11:03:10 AM
LastWriteTimeUtc : 7/28/2014 3:03:10 PM
Attributes : Directory
BaseName : temp
Mode : d----
The output I am expecting is:
Mode LastWriteTime Length Name
---- ------------- ------ ----
d---- 7/28/2014 11:03 AM temp
If I pipe the output of LoadWithPartialName to Out-Null, then I do get the expected output. I would like to understand what is happening here so I can anticipate these discrepancies in the future.

I think I figured this out.
In the original case with the LoadWithPartialName, the output of the script is an array of PSObject since Powershell sends any unhandled object to the pipeline, and the items are of mixed types (0 = AssemblyInfo from Load; 1 = DirectoryInfo from new-item).
If you redirect the LoadWithPartialName to [void] or even save the output in a variable, the output of the script is a single DirectoryInfo object.
PSObject gets formatted differently than DirectoryInfo

Related

How do I open a folder link in powershell/windows terminal?

When I type the obvious thing
PS > cd folderName.lnk
or
PS > cd folderName.lnk
in both cases it claims that the file doesn't exist, even though 'ls' shows that it does. Any suggestions? Thank you
try this:
$sh = New-Object -ComObject WScript.Shell
$target = $sh.CreateShortcut('<full-path-to-shortcut>').TargetPath
set-location -LiteralPath $target
make sure you use the full path to the shortcut, not a relative path like .\FolderName.lnk
you can also script it so you always get the absolute path:
$shortcut = '.\Shortcut.lnk'
$absolutepath = Convert-Path -Path $shortcut
$sh = New-Object -ComObject WScript.Shell
$target = $sh.CreateShortcut($absolutepath).TargetPath
Set-Location -LiteralPath $target
As noted by others, .lnk files are not directories,...
Get-ChildItem -Path "$env:USERPROFILE\Desktop"
# Results
<#
Directory: C:\Users\WDAGUtilityAccount\Desktop
Mode LastWriteTime Length Name
---- ------------- ------ ----
-a---- 1/2/2023 1:39 PM 737 Scripts.lnk
#>
...so you cannot directly navigate to them with any directory-like command.
The Desktop is the folder for that file.
(Get-ChildItem -Path "$env:USERPROFILE\Desktop").Fullname
# Results
<#
C:\Users\WDAGUtilityAccount\Desktop\Scripts.lnk
#>
Get-ChildItem -Path "$env:USERPROFILE\Desktop" |
Select-Object -Property '*'
# Results
<#
PSPath : Microsoft.PowerShell.Core\FileSystem::C:\Users\WDAGUtilityAccount\Desktop\Scripts.lnk
PSParentPath : Microsoft.PowerShell.Core\FileSystem::C:\Users\WDAGUtilityAccount\Desktop
PSChildName : Scripts.lnk
PSDrive : C
PSProvider : Microsoft.PowerShell.Core\FileSystem
PSIsContainer : False
Mode : -a----
VersionInfo : File: C:\Users\WDAGUtilityAccount\Desktop\Scripts.lnk
InternalName:
OriginalFilename:
FileVersion:
FileDescription:
Product:
ProductVersion:
Debug: False
Patched: False
PreRelease: False
PrivateBuild: False
SpecialBuild: False
Language:
BaseName : Scripts
Target : {}
LinkType :
Name : Scripts.lnk
Length : 737
DirectoryName : C:\Users\WDAGUtilityAccount\Desktop
Directory : C:\Users\WDAGUtilityAccount\Desktop
IsReadOnly : False
Exists : True
FullName : C:\Users\WDAGUtilityAccount\Desktop\Scripts.lnk
Extension : .lnk
CreationTime : 1/2/2023 1:39:41 PM
CreationTimeUtc : 1/2/2023 9:39:41 PM
LastAccessTime : 1/2/2023 1:39:43 PM
LastAccessTimeUtc : 1/2/2023 9:39:43 PM
LastWriteTime : 1/2/2023 1:39:41 PM
LastWriteTimeUtc : 1/2/2023 9:39:41 PM
Attributes : Archive
#>
So, you have to extract that FQDN from the link and use the available directory/Name commands to navigate to that path.

How to find the title for a PDF from the metadata?

How can I get the title for a PDF file after having renamed the file itself?
PSPath : Microsoft.PowerShell.Core\FileSystem::/home/nicholas/to/99.pdf
PSParentPath : Microsoft.PowerShell.Core\FileSystem::/home/nicholas/to
PSChildName : 99.pdf
PSDrive : /
PSProvider : Microsoft.PowerShell.Core\FileSystem
PSIsContainer : False
Mode : -----
ModeWithoutHardLink : -----
VersionInfo : File: /home/nicholas/to/99.pdf
InternalName:
OriginalFilename:
FileVersion:
FileDescription:
Product:
ProductVersion:
Debug: False
Patched: False
PreRelease: False
PrivateBuild: False
SpecialBuild: False
Language:
BaseName : 99
Target :
LinkType :
Length : 592483
DirectoryName : /home/nicholas/to
Directory : /home/nicholas/to
IsReadOnly : False
FullName : /home/nicholas/to/99.pdf
Extension : .pdf
Name : 99.pdf
Exists : True
CreationTime : 2/19/2021 11:45:18 PM
CreationTimeUtc : 2/20/2021 7:45:18 AM
LastAccessTime : 2/20/2021 2:02:36 AM
LastAccessTimeUtc : 2/20/2021 10:02:36 AM
LastWriteTime : 2/19/2021 11:45:18 PM
LastWriteTimeUtc : 2/20/2021 7:45:18 AM
Attributes : Normal
PS /home/nicholas/to>
PS /home/nicholas/to> Get-ChildItem -Path ./ –File | Select-Object -Property *
This is to bulk import PDF files into calibre, which, notably, seems to recognize duplicates and even displays some titles. Is it parsing the PDF file itself, or gleaning this from meta-data?
For this, you can use pdfinfo.exe which you can find as part of the free Xpdf command line tools.
After you have downloaded and extracted the zip file, copy pdfinfo.exe to some directory and make sure you unblock it, either by right-click or by using PowerShell
Unblock-File -Path 'Where\Ever\You\Have\Copied\It\To\pdfinfo.exe'
Using that, to get the original title as stored in the pdf, you do
$title = ((& 'D:\Test\pdfinfo.exe' 'D:\Test\test.pdf' |
Where-Object { $_ -match '^Title:' }) -split ':', 2)[-1].Trim()

In PowerShell why does "casting" to FileInfo set the wrong FullName, Directory, and DirectoryName

I'm noticing a VERY odd behavior in both my PS ISE and PS when I'm getting a FileInfo object by calling
$FileInfo = [System.IO.FileInfo](".\SomeFile.ext")
When I look at its properties the DirectoryName and its related properties all default to the ORIGINAL path that PS opens in.
Here's a copy from my ISE which launches as an administrator with c:\Windows\System32 as the default path
If I run the following code:
$Fileinfo = [System.IO.FileInfo](".\#OpenWithToastLogo.png")
cd c:\temp
$Fileinfo2 = [System.IO.FileInfo](".\activation.txt")
z:
$Fileinfo3 = [System.IO.FileInfo](".\7za.exe")
$Fileinfo | fl *
$Fileinfo2 | fl *
$Fileinfo3 | fl *
I get
VersionInfo :
File : C:\WINDOWS\system32\#OpenWithToastLogo.png
InternalName :
OriginalFilename :
FileVersion :
FileDescription :
Product :
ProductVersion :
Debug : False
Patched : False
PreRelease : False
PrivateBuild : False
SpecialBuild : False
Language :
BaseName : #OpenWithToastLogo
Target : {C:\Windows\WinSxS\wow64_microsoft-windows-openwith_31bf3856ad364e35_10.0.10240.16384_none_7f75eaad41c1f239\#OpenWithToastLogo.png,C:\Windows\SysWOW64\#OpenWithToastLogo.png}
LinkType : HardLink
Mode : -a---l
Name : #OpenWithToastLogo.png
Length : 160
DirectoryName : C:\WINDOWS\system32
Directory : C:\WINDOWS\system32
IsReadOnly : False
Exists : True
FullName : C:\WINDOWS\system32\#OpenWithToastLogo.png
Extension : .png
CreationTime : 7/10/2015 7:00:32 AM
CreationTimeUtc : 7/10/2015 11:00:32 AM
LastAccessTime : 7/10/2015 7:00:32 AM
LastAccessTimeUtc : 7/10/2015 11:00:32 AM
LastWriteTime : 7/10/2015 7:00:32 AM
LastWriteTimeUtc : 7/10/2015 11:00:32 AM
Attributes : Archive
VersionInfo :
BaseName : activation
Target :
LinkType :
Mode : darhsl
Name : activation.txt
Length :
DirectoryName : C:\WINDOWS\system32
Directory : C:\WINDOWS\system32
IsReadOnly : True
Exists : False
FullName : C:\WINDOWS\system32\activation.txt
Extension : .txt
CreationTime : 12/31/1600 7:00:00 PM
CreationTimeUtc : 1/1/1601 12:00:00 AM
LastAccessTime : 12/31/1600 7:00:00 PM
LastAccessTimeUtc : 1/1/1601 12:00:00 AM
LastWriteTime : 12/31/1600 7:00:00 PM
LastWriteTimeUtc : 1/1/1601 12:00:00 AM
Attributes : -1
VersionInfo :
BaseName :
7za Target :
LinkType :
Mode : darhsl
Name : 7za.exe
Length :
DirectoryName : C:\WINDOWS\system32
Directory : C:\WINDOWS\system32
IsReadOnly : True
Exists : False
FullName : C:\WINDOWS\system32\7za.exe
Extension : .exe
CreationTime : 12/31/1600 7:00:00 PM
CreationTimeUtc : 1/1/1601 12:00:00 AM
LastAccessTime : 12/31/1600 7:00:00 PM
LastAccessTimeUtc : 1/1/1601 12:00:00 AM
LastWriteTime : 12/31/1600 7:00:00 PM
LastWriteTimeUtc : 1/1/1601 12:00:00 AM
Attributes : -1
With my regular account it defaults to my H:\ path so the same test would have H:\ as the DirectoryName.
And yes, each of these files ONLY exists in the directory it was relative to.
Has anyone seen this before, and do they know a good fix? Using fully qualified of course works but this is for a script that other technicians might run and we're all pretty used to the idea of using relative pathing with PS.
PowerShell has a notion of your current location. You can see this
using the $pwd automatic variable or the Get-Location cmdlet [..]
This path is used by PowerShell to resolve relative paths at the level of
the PowerShell API.
[..]
Applications have a notion of the current directory. This is the
directory used to resolve relative paths at the level of the Windows
API.
How you Get Burned
Your current location may or may not be the same as your current directory.
From http://www.beefycode.com/post/The-Difference-between-your-Current-Directory-and-your-Current-Location.aspx
and
One question that comes up frequently is, “Why does PowerShell not
change its [System.Environment]::CurrentDirectory as I navigate around
the shell?”
One of the difficult aspects of this comes from the fact that
PowerShell supports multiple pipelines of execution. Although it’s
not directly exposed yet, users will soon be able to suspend jobs to
the background, and other concurrent tasks.
The current directory affects the entire process, so if we change the
directory as you navigate around the shell, you risk corrupting the
environment of jobs you have running in the background.
When you use filenames in .Net methods, the best practice is to use
fully-qualified path names. The Resolve-Path cmdlet makes this easy:
$reader = new-object System.Xml.XmlTextReader (Resolve-Path baseline.xml)
From http://www.leeholmes.com/blog/2006/07/18/set-location-and-environmentcurrentdirectory/

Select-Object - what can I select?

I'm learning PowerShell and I am stuck at an issue where I have to export something and I don't know its object name.
I use this command:
Get-Mailbox -ResultSize Unlimited | Select-Object DisplayName,PrimarySmtpAddress
How do I find out what objects I can select with Select-Object?
Use Get-Member.
Get-Mailbox -ResultSize Unlimited | Get-Member
will show you all of the properties (as well as methods and events).
Get-member will show you all of the properties and methods of an object, but it doesn't show you the values. To see the values, I recommend using Format-List instead.
For example, Get-ChildItem (Dir) shows you a list of files, but also provides a tremendous amount of other properties we might want. To see them all, pipe it into format-list.
PS C:\temp\NewFolder> dir
Directory: C:\temp\NewFolder
Mode LastWriteTime Length Name
---- ------------- ------ ----
-a---- 7/22/2015 11:31 AM 44 Computers.txt
-a---- 7/22/2015 12:37 PM 106 NotepadProfile.ps1
-a---- 7/22/2015 11:07 AM 21 Tester.txt
Not bad, and a pretty useful listing, but to see everything we have to work with, throwing Format-List (FL) is the way to go.
PS C:\temp\NewFolder> dir | format-list *
PSPath : Microsoft.PowerShell.Core\FileSystem::C:\temp\NewFolder\Computers.txt
PSParentPath : Microsoft.PowerShell.Core\FileSystem::C:\temp\NewFolder
PSChildName : Computers.txt
PSDrive : C
PSProvider : Microsoft.PowerShell.Core\FileSystem
PSIsContainer : False
VersionInfo : File: C:\temp\NewFolder\Computers.txt
InternalName:
OriginalFilename:
FileVersion:
FileDescription:
Product:
ProductVersion:
Debug: False
Patched: False
PreRelease: False
PrivateBuild: False
SpecialBuild: False
Language:
BaseName : Computers
Target :
LinkType :
Mode : -a----
Name : Computers.txt
Length : 44
DirectoryName : C:\temp\NewFolder
Directory : C:\temp\NewFolder
IsReadOnly : False
Exists : True
FullName : C:\temp\NewFolder\Computers.txt
Extension : .txt
CreationTime : 7/22/2015 11:13:40 AM
CreationTimeUtc : 7/22/2015 3:13:40 PM
LastAccessTime : 7/22/2015 11:13:40 AM
LastAccessTimeUtc : 7/22/2015 3:13:40 PM
LastWriteTime : 7/22/2015 11:31:33 AM
LastWriteTimeUtc : 7/22/2015 3:31:33 PM
Attributes : Archive

PowerShell New-Item output is inconsistent - Why?

I am getting different out for the same powershell command and I am not sure why.
When this runs within a function, I get output 1 and when I run by itself I get output2
New-Item -Path C:\DEPL\nichdwww\deployments\Full\bob3 -type directory
Output 1
PSPath : Microsoft.PowerShell.Core\FileSystem::C:\DEPL\nichdwww\deployments\Full\bob3
PSParentPath : Microsoft.PowerShell.Core\FileSystem::C:\DEPL\nichdwww\deployments\Full
PSChildName : bob3
PSDrive : C
PSProvider : Microsoft.PowerShell.Core\FileSystem
PSIsContainer : True
Name : bob3
Parent : Full
Exists : True
Root : C:\
FullName : C:\DEPL\nichdwww\deployments\Full\bob3
Extension :
CreationTime : 6/23/2015 2:14:39 PM
CreationTimeUtc : 6/23/2015 6:14:39 PM
LastAccessTime : 6/23/2015 2:14:39 PM
LastAccessTimeUtc : 6/23/2015 6:14:39 PM
LastWriteTime : 6/23/2015 2:14:39 PM
LastWriteTimeUtc : 6/23/2015 6:14:39 PM
Attributes : Directory
BaseName : bob3
Mode : d----
Output 2
Directory: C:\DEPL\nichdwww\deployments\Full
Mode LastWriteTime Length Name
---- ------------- ------ ----
d---- 6/23/2015 2:45 PM bob3
Here is the function
function ArchiveFullSolution($wsp)
{
$ParentPath=Split-Path $wsp.DirectoryName -Parent
$FullPath=$ParentPath+'\Full\'
$Fullfilename=$FullPath+$wsp.Name
#$Fullfilename
#does file exist
if(Test-Path -path $Fullfilename)
{
#Make Full Archive folder
#$script:Makefolder
if($script:Makefolder)
{
#does folder exists
$DayFormat=Get-Date -f yyyy-MM-dd
if(Test-Path -path $FullPath$DayFormat)
{
write-host "folder $FullPath$DayFormat exists"
$DayTimeFormat=Get-Date -f yyyy-MM-dd-hh-mm
write-host "Creating folder $FullPath$DayTimeFormat"
New-Item -Path $FullPath$DayTimeFormat -type directory
$script:Makefolder=$false
$script:FullArchivePath=$FullPath+$DayTimeFormat
}
else
{
write-host "no folder exists"
write-host "Creating folder $FullPath$DayFormat"
New-Item -Path $FullPath$DayFormat -type directory
$script:Makefolder=$false
$script:FullArchivePath=$FullPath+$DayFormat
}
}
#move file into archive
Move-Item $Fullfilename $script:FullArchivePath
write-host "Moving file $($Fullfilename) to $FullArchivePath"
}
#copy file into full
Copy-Item $wsp.FullName $FullPath
write-host "Copying file $($wsp.FullName) to $FullPath"
}
Check your function. Most likely it is outputting another object first. After the PowerShell F&O (formatting and output) engine sees one type of object it wants to format everything after that like that type. If it then sees another type of object, it will fall back to using Format-List IIRC.