Microsoft project open files using powershell - powershell

I'm having problem opening project file from Project Online (server). I want to save all online files locally. If I open project first through Desktop client and try to open that file using function FileOpenEx it works (maybe because it opens draft?)
Also I've tried full URL
$Project.FileOpenEx(".../pwa/_api/projectdata/Projects/$name",$true)
But it started import wizard
This is the code:
$csv = Import-Csv '...\ProjectNames.csv'
$Project = New-Object -ComObject msproject.application
$csv | ForEach-Object {
$name=$_.ProjectName
Write-Output $name
$Project.FileOpenEx("<>\$name",$true)
$Save=$Project.FileSaveAs("...\Desktop\ProjectData\$name.mpp")
Get-Process | where{$_.ProcessName -like "*winproj*"} | Stop-Process
}
I get this error when I try to open Project Online projects.
ForEach-Object : Exception calling "FileOpenEx" with "2" argument(s): "The remote procedure call failed. (Exception from HRESULT: 0x800706BE)"
At ...\MigrateProjects.ps1:26 char:8
+ $csv | ForEach-Object {
+ ~~~~~~~~~~~~~~~~
+ CategoryInfo : NotSpecified: (:) [ForEach-Object], MethodInvocationException
+ FullyQualifiedErrorId : COMException,Microsoft.PowerShell.Commands.ForEachObjectCommand
EDIT: I've changed code to use shell like pointed in comments and it opens now. But when I try to save file sometimes it doesn't return boolean value and just stops. It happens on different projects, but it did save all my listed projects once. But when I want to repeat saving process it just exits at FileSaveAs. And I can't figure out why.
$csv = Import-Csv '...\ProjectData\ProjectNames.csv'
$ProjServer=".../sites/pwa/"
$ProjShell = new-object -comobject wscript.shell
$ProjShell.Run("winproj /s $ProjServer", 1,$false)
Start-Sleep -s 15
$Project =[System.Runtime.InteropServices.Marshal]::GetActiveObject("msproject.application")
Try{
$csv | ForEach-Object {
$name=$_.ProjectName
Write-Output $name
$NameWithoutSpaces= $name -replace '\s','_'
$Project.FileOpenEx("<>\$name",$true)
$Save= $Project.FileSaveAs("...\ProjectData\$NameWithoutSpaces.mpp")
Write-Output $Save
}
}
catch{
Get-Process | where{$_.ProcessName -like "*winproj*"} | Stop-Process
$error[0].Exception.GetBaseException().LoaderExceptions
}
Get-Process | where{$_.ProcessName -like "*winproj*"} | Stop-Process

Related

unable to export from powershell to CSV [duplicate]

This question already has answers here:
Writing console output to a file - file is unexpectedly empty
(2 answers)
Closed 3 years ago.
Pls help a poor newby over here...below is my script with the errors at the bottom of the script. The main issue is that i am unable to export to CSV
PS C:\Users\LUPUWANA> $logs = get-eventlog system -ComputerName cafeserver -source Microsoft-Windows-Winlogon -After (Get-Date).AddDays(-7);
$res = #(); ForEach ($log in $logs) {if($log.instanceid -eq 7001) {$type = "Logon"} Elseif ($log.instanceid -eq 7002){$type="Logoff"} Else {Continue} $res += New-Object PSObject -Property #{Time = $log.TimeWritten; "Event" = $type; User = (New-Object System.Security.Principal.SecurityIdentifier $Log.ReplacementStrings[1]).Translate([System.Security.Principal.NTAccount])}};
Export-Csv -Path C:\users\lupuwana\desktop\events.csv
oss get-help -detailed
Supply values for the following parameters:
InputObject:
oss : Cannot process argument transformation on parameter 'Width'. Cannot convert value "get-help" to type "System.Int32". Error: "Input string was not in a
correct format."
At line:4 char:5
+ oss get-help -detailed
+ CategoryInfo : InvalidData: (:) [oss], ParameterBindingArgumentTransformationException
+ FullyQualifiedErrorId : ParameterArgumentTransformationError,oss
Your loop builds an object called $res, so assuming that's the object you wish to export to CSV, you need to supply that object to the Export-Csv Cmdlet:
Export-Csv -InputObject $res -Path C:\users\lupuwana\desktop\events.csv
You may also wish to add the -NoTypeInformation option too otherwise your file will contain an extra header row describing the object type.

Powershell ZIP CopyHere counteracting asynchronous behavior

Within Powershell, the CopyHere method for the Shell-Application Namespace is asynchronous. My main goal with this is to convert a KML file to a KMZ file. The process of doing this is to create a ZIP file with the same name, copy the KML into the KMZ (compresses the file) and then rename the ZIP to KMZ. Unfortunately, being asynchronous means the rename function is being called before the CopyHere method is completed. I have found many examples of solving this. The cleanest one I found is below:
$kmlPath = $global:directoryPath + "Test.kml"
$zip = $global:directoryPath + "Test.zip"
New-Item $zip -ItemType file
$shellApplication = new-object -com shell.application
$zipPackage = $shellApplication.NameSpace($zip)
$zipPackage.CopyHere($kmlPath, 16)
while($zipPackage.Items().Item($zip.Name) -Eq $null)
{
start-sleep -seconds 1
write-host "." -nonewline
}
write-host "."
Rename-Item -Path $zip -NewName $([System.IO.Path]::ChangeExtension($zip, ".kmz"))
This responds with the following error:
Exception calling "Item" with "1" argument(s): "Not implemented
(Exception from HRESULT: 0x80004001 (E_NOTIMPL))"
+ while($zipPackage.Items().Item($zip.Name) -Eq $null)
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : NotSpecified: (:) [], MethodInvocationException
+ FullyQualifiedErrorId : ComMethodTargetInvocation
Am I misusing the Item method for this particular package? I am confused why something that "appears" to be neatly done is not working. I have also tried the snippet of code provided Here. It also complains about the .Item method in this particular situation.
The issue i ran into was trying to find away to check on zip status.
So instead i did a trigger for a while that would fire ...If the Zipfile was openable and the File name was inside.
function kml_to_kmz([string]$kmlPath){
[Reflection.Assembly]::LoadWithPartialName('System.IO.Compression.FileSystem')
$kmlInfo = Get-ChildItem -Path $kmlPath
$zipLocation = ($kmlInfo.Directory.FullName + '\' + $kmlInfo.Name.Remove($kmlInfo.Name.LastIndexOf('.')) + '.zip')
New-item $zipLocation
((new-object -com shell.application).NameSpace($zipLocation)).CopyHere($kmlPath, 16)
$trigger = $false
while ($trigger -eq $false){
try{
$zip = [IO.Compression.ZipFile]::OpenRead($zipLocation)
If(($zip.Entries | %{$_.Name}) -contains $kmlInfo.Name){
$zip.Dispose();
$trigger = $true
break;
}
}catch{}
start-sleep -seconds 1
write-host "." -nonewline
}
[IO.Compression.ZipFile]::OpenRead($zipLocation).Dispose()
Rename-Item -Path $zipLocation -NewName $([System.IO.Path]::ChangeExtension($zipLocation, '.kmz'))
}
kml_to_kmz -kmlPath "C:\Users\Default\Desktop\Test.kml"

Why does the exception not get me in the catch block?

I'm trying to interrogate some service information. Sometimes the installer of the application fails to correctly install, so the registry does not contain a service entry. I want to find out which installer steps did get executed correctly, even on systems that do not have proper logging in the installer.
If MyService does not exist, the script below does not go to the catch block even though the exception handling documentation suggests a bare catch should be enough:
try {
$path = 'hklm:\SYSTEM\CurrentControlSet\services\MyService'
$key = Get-Item $path
$namevalues = $key | Select-Object -ExpandProperty Property |
ForEach-Object {
[PSCustomObject] #{
Name = $_;
Value = $key.GetValue($_)
}
}
$namevalues | Format-Table
}
catch {
$ProgramFilesX86 = [System.Environment]::GetFolderPath("ProgramFilesX86");
$ProgramFiles = [System.Environment]::GetFolderPath("ProgramFiles");
Write-Host $ProgramFilesX86
Write-Host $ProgramFiles
}
Why is that and how should I force it to end up in the catch?
This is what PowerShell outputs:
Get-Item : Cannot find path 'HKLM:\SYSTEM\CurrentControlSet\services\MyService' because it does not exist.
At C:\Users\Developer\...\GetMyServiceInfo.ps1:17 char:12
+ $key = Get-Item $path
+ ~~~~~~~~~~~~~~
+ CategoryInfo : ObjectNotFound: (HKLM:\SYSTEM\Cu...vices\MyService:String) [Get-Item], ItemNotFoundException
+ FullyQualifiedErrorId : PathNotFound,Microsoft.PowerShell.Commands.GetItemCommand
Force the error to be terminating:
$key = Get-Item $path -ErrorAction Stop
That way it will throw and catch will get it.
Explanation and links to the official Microsoft documentation:
-ErrorAction is a Common Parameter that can be applied to any PowerShell command
The default value for -ErrorAction is Continue which prevented the exception to be thrown in the first place.
You can configure a global -ErrorAction setting using the Preference Variable named $ErrorActionPreference to override this default value.

Powershell Error for Get-Service

Back when I had Windows 7 an a lower version of Powershell the following code use to work without any issues.
It checks each server in a text file for some services and dumps the results to a CSV.
Now that I'm on Windows 10 and with Powershell v5 I get this error message:
Get-Service : Cannot open Service Control Manager on computer 'tfsserver1'. This operation might require other privileges. At
C:\Users\Razon\Desktop\Patching\ServerServices_Checker_v2.ps1:48
char:4
+ (Get-Service -Name TFSJobAgent*,IIS*,World* -ComputerName $_) | Select Machine ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : NotSpecified: (:) [Get-Service], InvalidOperationException
+ FullyQualifiedErrorId : System.InvalidOperationException,Microsoft.PowerShell.Commands.GetServiceCommand
####System Varialbe to User's Deskotp
$filePath = [Environment]::GetFolderPath("Desktop")
Here is the code:
function tfsCheck
{
$Path = "$filePath\Patching\Servers\tfs_servers.txt"
Get-Content $Path | foreach {
(Get-Service -Name TFSJobAgent*,IIS*,World* -ComputerName $_) | Select MachineName, Status, DisplayName
}
}
#TFS Function Call and Write to CSV
tfsCheck|Select MachineName, Status, DisplayName |Export-Csv $filePath\Patching\Results\TFS_ServicesResults.csv -NoTypeInformation
To resolve this issue, elevate the user's network privileges to be able to access the Service Control Manager on the Server.
https://support.microsoft.com/en-in/help/964206/cannot-open-service-control-manager-on-computer-servername-.-this-operation-might-require-other-privileges

PS Get-WinEvent throw 'The Handle is invalid'

I have a list of hostnames from which I'd like to extract all AppLocker related eventlogs, especially the ones with level warning and/or error.
I crafted this script:
$ComputersToCheck = Get-Content 'X:\ListWithTheNames.txt'
foreach($OneHost in $ComputersToCheck)
{
try
{
$EventCollection = Get-WinEvent -LogName "Microsoft-Windows-AppLocker/EXE and DLL" -ComputerName $OneHost -Credential $CredentialFromUser
foreach ($SingelEvent in $EventCollection)
{
if($SingelEvent.LevelDisplayName -ne "Information")
{
$pathtosaveto = 'SomeFileName.txt'
$ResultString += $SingelEvent | Select Message,MachineName,UserId | Export-Csv -Path $pathtosaveto -Append
}
}
}
catch
{
//handling exceptions
}
}
This works for a while, but after a certain ammount of time I got an error:
Get-WinEvent : The remote procedure call failed
At X:\FileName.ps1:22 char:28
+ $EventCollection = Get-WinEvent -LogName "Microsoft-Windows-AppLocker/EX ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : NotSpecified: (:) [Get-WinEvent], EventLogException
+ FullyQualifiedErrorId : The remote procedure call failed,Microsoft.PowerShell.Commands.GetWinEventCommand
And right after the script start giving errors like this:
Get-WinEvent : The handle is invalid
At X:\FileName.ps1:22 char:28
+ $EventCollection = Get-WinEvent -LogName "Microsoft-Windows-AppLocker/EX ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : NotSpecified: (:) [Get-WinEvent], EventLogException
+ FullyQualifiedErrorId : The handle is invalid,Microsoft.PowerShell.Commands.GetWinEventCommand
My first thought was that it is related to the host the script try to reach, but the next in the list is the same type (Os, even the same model) as the previous.
I ran the script 3 times, and every time the output size was different (probably because not the same hosts were online with the same amount of logs).
The script should run against more than 700 hosts, to which a special account is needed which I prompt by the Get-Credential, store in a variable and pass it the the Get-WinEvent as a parameter.
To be honest I stuck with this issue, not really sure what cause this and why.
If anyone has an idea please share with me :)
Give this a try to attempt catching references to failed hosts and empty objects. You could write the exception received but I didn't include that in this to make the failedhosts file simple to read. Hope I got it right as I winged it and don't have a true case to test against.
$ComputersToCheck = Get-Content 'X:\ListWithTheNames.txt'
foreach($OneHost in $ComputersToCheck) {
try {
$EventCollection = Get-WinEvent -LogName "Microsoft-Windows-AppLocker/EXE and DLL" -ComputerName $OneHost -Credential $CredentialFromUser -ErrorAction Stop
if($EventCollection) {
foreach ($SingelEvent in $EventCollection) {
if($SingelEvent.LevelDisplayName -ne "Information") {
$pathtosaveto = 'SomeFileName.txt'
$ResultString += $SingelEvent | Select Message,MachineName,UserId | Export-Csv -Path $pathtosaveto -Append
}
}
} else {
Out-File -InputObject $($OneHost + " Empty Event Collection") -FilePath "C:\FailedHosts.txt" -Append -Encoding ascii
}
}
catch {
Out-File -InputObject $($OneHost + " Failed Connection") -FilePath "C:\FailedHosts.txt" -Append -Encoding ascii
}
}