diff --git a/Sources/OneDrive.psd1 b/Sources/OneDrive.psd1 index 058afc4..5cd9ca8 100644 Binary files a/Sources/OneDrive.psd1 and b/Sources/OneDrive.psd1 differ diff --git a/Sources/OneDrive.psm1 b/Sources/OneDrive.psm1 index 50891f0..1238c69 100644 --- a/Sources/OneDrive.psm1 +++ b/Sources/OneDrive.psm1 @@ -1,5 +1,60 @@ + +function ConvertTo-jwt { +PAram([Parameter(Mandatory=$true,ValueFromPipeline=$true)][string]$data) +if (-not($data)){Write-Error "没有输入值,例如:JWTxxxxxxxx.....";break;} +[array]$data=$data -split '\.' +function frombase64 { +param([Parameter(Position = 0, ValueFromPipeline = $True)] +[string]$a) +$c=$a.Length +if((4 -lt $c) -and(0 -ne $c%4)){$b=4-$c%4}elseif($c -lt 4){$b=4-$c}else{$b=0} +[System.Text.Encoding]::Utf8.GetString([System.Convert]::FromBase64String($a+("="*$b)))} +$base=@() +for($i=0;$I -lt ($data.length -1);$i++){ +frombase64 $data[$i]|convertfrom-json +}} + +function Get-HashValue {param( +[ValidateScript( + { + if (test-path $_ -PathType Leaf ) + { + $true + } + else + { + Throw "file does not exist" + } + })] +[Parameter(Mandatory=$true)] +$file) +$file=Resolve-Path $file +$buf=[byte[]]::new(1mb) +$fd=[IO.FileStream]::new($file, [IO.FileMode]::Open) +$md5=[System.Security.Cryptography.MD5]::Create() +$fd.Read($buf,0,$buf.length)|set-variable -name length|out-null +$object=[PScustomobject]@{filelength=($fd.length -1)} +$fd.close() +$object|add-member @{hash=[System.BitConverter]::ToString($md5.ComputeHash($buf))} +$object|add-member @{file=$file} +$object +} + +function splash{ + $a=@{ EnableGlobalVariable=$true} + $b=@{} + $Authentication|get-member -MemberType NoteProperty|ForEach-Object{ + if(@( "ResourceId", "Scope", "RedirectURI", "AppKey", "Refresh_Token", "ClientId") -contains $_.name){ + $b+=@{[string]$($_.name -replace '_')=[string]$Authentication.$($_.name)}}} + if($ResourceId){ + if($ResourceId -eq $Authentication.ResourceId){$a+=$b}else{$null=Get-ODAuthentication -ResourceId $ResourceId} + }else{$a+=$b} + $null=Get-ODAuthentication @a +} + function Get-ODAuthentication { +# .ExternalHelp OneDrive-help.xml <# .DESCRIPTION Connect to OneDrive for authentication with a given client id (get your free client id on https://apps.dev.microsoft.com) For a step-by-step guide: https://github.com/MarcelMeurer/PowerShellGallery-OneDrive @@ -12,15 +67,15 @@ function Get-ODAuthentication .PARAMETER Scope Comma-separated string defining the authentication scope (https://dev.onedrive.com/auth/msa_oauth.htm). Default: "onedrive.readwrite,offline_access". Not needed for OneDrive 4 Business access. .PARAMETER RefreshToken - Refreshes the authentication token unattended with this refresh token. + Refreshes the authentication token unattended with this refresh token. .PARAMETER AutoAccept In token mode the accept button in the web form is pressed automatically. .PARAMETER RedirectURI - Code authentication requires a correct URI. Use the same as in the app registration e.g. http://localhost/logon. Default is https://login.live.com/oauth20_desktop.srf. Don't use this parameter for token-based authentication. + Code authentication requires a correct URI. Use the same as in the app registration e.g. http://localhost/logon. Default is https://login.live.com/oauth20_desktop.srf. Don't use this parameter for token-based authentication. .PARAMETER DontShowLoginScreen - Suppresses the logon screen. Be careful: If you suppress the logon screen you cannot logon if your credentials are not passed through. + Suppresses the logon screen. Be careful: If you suppress the logon screen you cannot logon if your credentials are not passed through. .PARAMETER LogOut - Performs a logout. + Performs a logout. .EXAMPLE $Authentication=Get-ODAuthentication -ClientId "0000000012345678" @@ -30,17 +85,43 @@ function Get-ODAuthentication Author: Marcel Meurer, marcel.meurer@sepago.de, Twitter: MarcelMeurer #> PARAM( - [Parameter(Mandatory=$True)] + [Parameter(Mandatory=$True,HelpMessage="ClientId of your 'app' from https://apps.dev.microsoft.com,'93xxxx81-2a8a-46d7-8524-9xxe07c6xxx0'")] + [ValidateScript( + { + if ($_ -cmatch '([a-f0-9]{4,}-?){4,}') + { + $true + } + else + { + Throw 'ClientId error' + } + })] [string]$ClientId = "unknown", [string]$Scope = "onedrive.readwrite,offline_access", [string]$RedirectURI ="https://login.live.com/oauth20_desktop.srf", [string]$AppKey="", [string]$RefreshToken="", + [ValidateScript( + { + if ($_ -cmatch '^h(\w)\1ps:\/\/[^,<>/]+?-my.sharepoint.com\/?$|^[^,/]{2,20}$') + { + $true + } + else + { + Throw 'Accepted value: "" or "https://-my.sharepoint.com/"' + } + })] [string]$ResourceId="", [switch]$DontShowLoginScreen=$false, [switch]$AutoAccept, - [switch]$LogOut + [switch]$LogOut, + [switch]$EnableGlobalVariable ) + if($ResourceId -cmatch '^[^,<>/]{2,20}$') + {$ResourceId="https://${ResourceId}-my.sharepoint.com/"} + #if($ClientId -cnotmatch '([a-f0-9]{4,}-?){4,}'){write-host 'ClientId error' -ForegroundColor red;break} $optResourceId="" $optOauthVersion="/v2.0" if ($ResourceId -ne "") @@ -51,25 +132,33 @@ function Get-ODAuthentication } $Authentication="" if ($AppKey -eq "") - { + { $Type="token" - } else - { + } else + { $Type="code" } if ($RefreshToken -ne "") { write-debug("A refresh token is given. Try to refresh it in code mode.") $body="client_id=$ClientId&redirect_URI=$RedirectURI&client_secret=$([uri]::EscapeDataString($AppKey))&refresh_token="+$RefreshToken+"&grant_type=refresh_token" - write-host $body + write-debug $body $webRequest=Invoke-WebRequest -Method POST -Uri "https://login.microsoftonline.com/common/oauth2$optOauthVersion/token" -ContentType "application/x-www-form-URLencoded" -Body $Body -UseBasicParsing $Authentication = $webRequest.Content | ConvertFrom-Json } else { write-debug("Authentication mode: " +$Type) - [Reflection.Assembly]::LoadWithPartialName("System.Windows.Forms") | out-null - [Reflection.Assembly]::LoadWithPartialName("System.Drawing") | out-null - [Reflection.Assembly]::LoadWithPartialName("System.Web") | out-null + try{ + new-object System.Windows.Forms|out-null + }catch{ + Write-Warning $_.Exception.Message + $Verify=1 + } + if($Verify -ne 1){ + [Reflection.Assembly]::LoadWithPartialName("System.Windows.Forms") + [Reflection.Assembly]::LoadWithPartialName("System.Drawing") + [Reflection.Assembly]::LoadWithPartialName("System.Web") + } if ($Logout) { $URIGetAccessToken="https://login.live.com/logout.srf" @@ -87,6 +176,7 @@ function Get-ODAuthentication $URIGetAccessToken="https://login.live.com/oauth20_authorize.srf?client_id="+$ClientId+"&scope="+$Scope+"&response_type="+$Type+"&redirect_URI="+$RedirectURI } } + if($Verify -ne 1){ $form = New-Object Windows.Forms.Form $form.text = "Authenticate to OneDrive" $form.size = New-Object Drawing.size @(700,600) @@ -106,12 +196,23 @@ function Get-ODAuthentication } $web.Add_DocumentCompleted($DocComplete) $form.Controls.Add($web) - if ($DontShowLoginScreen) + if ($DontShowLoginScreen -or -not($Verify)) { write-debug("Logon screen suppressed by flag -DontShowLoginScreen") $form.Opacity = 0.0; } $form.showdialog() | out-null + }else{ + @("A refresh token is given. Try to refresh it in code mode.",$URIGetAccessToken)|out-host + $regex= 'access_token=[^&]+|\?code=[^&]+' + do { + $key=read-host -prompt 'URL' + if (-not($key -match $regex)){write-host "`rERROR,Enter 'exit' to exit read-host" -ForegroundColor DarkCyan|out-host} + }until($key -match $regex) + $Global:ODAccessToken=($key|select-string -pattern '(?<=token=)[^&]+' ).matches.value + $Global:odtokentime=get-date + $web=[PSobject]@{Url=$key} + } # Build object from last URI (which should contains the token) $ReturnURI=($web.Url).ToString().Replace("#","&") if ($LogOut) {return "Logout"} @@ -119,7 +220,7 @@ function Get-ODAuthentication { write-debug("Getting code to redeem token") $Authentication = New-Object PSObject - ForEach ($element in $ReturnURI.Split("?")[1].Split("&")) + ForEach ($element in $ReturnURI.Split("?")[1].Split("&")) { $Authentication | add-member Noteproperty $element.split("=")[0] $element.split("=")[1] } @@ -135,7 +236,7 @@ function Get-ODAuthentication } else { $Authentication = New-Object PSObject - ForEach ($element in $ReturnURI.Split("?")[1].Split("&")) + ForEach ($element in $ReturnURI.Split("?")[1].Split("&")) { $Authentication | add-member Noteproperty $element.split("=")[0] $element.split("=")[1] } @@ -149,13 +250,48 @@ function Get-ODAuthentication { write-warning("There is maybe an errror, because there is no access_token!") } - return $Authentication + $Authentication | add-member Noteproperty "ClientId" ($ClientId) + if ($ResourceId){ + $Authentication | add-member Noteproperty "ResourceId" ($ResourceId) + } + if ($appkey){ + $Authentication | add-member Noteproperty "appkey" ($appkey) + } + if($EnableGlobalVariable){ + $Global:Authentication=$Authentication + } +<# +$URL=$Key -replace '[^#]+#' -split '&' -replace '^[^=]+$' -split '=' +$format=@() +for(($i=0),($j=1);$I -lt $URL.length;($i+=2),($j+=2)){ +$format+=@{$URL[$i]=$URL[$j]}} +$access_token=jwt-decode $format.access_token +$global:authen=jwt-decode $format.authentication_token +$global:authentication_token= +(Get-Date 01.01.1970)+([System.TimeSpan]::fromseconds($authen.exp[1])) +#> + return $Authentication } -function Get-ODRootUri +function Get-ODRootUri { PARAM( + [ValidateScript( + { + if ($_ -cmatch '^h(\w)\1ps:\/\/[^,<>/]+?-my.sharepoint.com\/?$|^[^,/]{2,20}$' -or $_ -eq '') + { + $true + } + else + { + Throw 'Accepted value: "" or "https://-my.sharepoint.com/"' + } + })] [String]$ResourceId="" ) + if($ResourceId -cmatch '^[^,<>/]{2,20}$') + {$ResourceId="https://${ResourceId}-my.sharepoint.com"} + if($ResourceId -cmatch 'https:\/\/[^,<>/]{2,20}-my.sharepoint.com$') + {$ResourceId=$($ResourceId -replace '(\w$)','$1/')} if ($ResourceId -ne "") { return $ResourceId+"_api/v2.0" @@ -166,7 +302,7 @@ function Get-ODRootUri } } -function Get-ODWebContent +function Get-ODWebContent { <# .DESCRIPTION @@ -187,52 +323,23 @@ function Get-ODWebContent Author: Marcel Meurer, marcel.meurer@sepago.de, Twitter: MarcelMeurer #> PARAM( - [Parameter(Mandatory=$True)] + [Parameter(Mandatory=$false)] [string]$AccessToken, [String]$ResourceId="", [string]$rURI = "", - [ValidateSet("PUT","GET","POST","PATCH","DELETE")] + [ValidateSet("PUT","GET","POST","PATCH","DELETE")] [String]$Method="GET", [String]$Body, [switch]$BinaryMode ) - if ($Body -eq "") + if ($Body -eq "") { $xBody=$null } else { $xBody=$Body } - $ODRootURI=Get-ODRootUri -ResourceId $ResourceId - try { - $webRequest=Invoke-WebRequest -Method $Method -Uri ($ODRootURI+$rURI) -Header @{ Authorization = "BEARER "+$AccessToken} -ContentType "application/json" -Body $xBody -UseBasicParsing -ErrorAction SilentlyContinue - } - catch - { - write-error("Cannot access the api. Webrequest return code is: "+$_.Exception.Response.StatusCode+"`n"+$_.Exception.Response.StatusDescription) - break - } - switch ($webRequest.StatusCode) - { - 200 - { - if (!$BinaryMode) {$responseObject = ConvertFrom-Json $webRequest.Content} - return $responseObject - } - 201 - { - write-debug("Success: "+$webRequest.StatusCode+" - "+$webRequest.StatusDescription) - if (!$BinaryMode) {$responseObject = ConvertFrom-Json $webRequest.Content} - return $responseObject - } - 204 - { - write-debug("Success: "+$webRequest.StatusCode+" - "+$webRequest.StatusDescription+" (item deleted)") - $responseObject = "0" - return $responseObject - } - default {write-warning("Cannot access the api. Webrequest return code is: "+$webRequest.StatusCode+"`n"+$webRequest.StatusDescription)} - } + getweb -Method $Method -Body $xBody -accesstoken $accesstoken -ResourceId $ResourceId } function Get-ODDrives @@ -252,11 +359,12 @@ function Get-ODDrives Author: Marcel Meurer, marcel.meurer@sepago.de, Twitter: MarcelMeurer #> PARAM( - [Parameter(Mandatory=$True)] + [Parameter(Mandatory=$false)] [string]$AccessToken, [String]$ResourceId="" ) - $ResponseObject=Get-ODWebContent -AccessToken $AccessToken -ResourceId $ResourceId -Method GET -rURI "/drives" + $ProgressPreference="SilentlyContinue" + $ResponseObject=Get-ODWebContent -AccessToken $AccessToken -ResourceId $ResourceId -Method GET -rURI "/drives" return $ResponseObject.Value } @@ -277,10 +385,11 @@ function Get-ODSharedItems Author: Marcel Meurer, marcel.meurer@sepago.de, Twitter: MarcelMeurer #> PARAM( - [Parameter(Mandatory=$True)] + [Parameter(Mandatory=$false)] [string]$AccessToken, [String]$ResourceId="" ) + $ProgressPreference="SilentlyContinue" $ResponseObject=Get-ODWebContent -AccessToken $AccessToken -ResourceId $ResourceId -Method GET -rURI "/drive/oneDrive.sharedWithMe" return $ResponseObject.Value } @@ -304,13 +413,17 @@ function Format-ODPathorIdString [string]$DriveId="", [string]$ElementId="" ) + if($Path -cmatch'(%[A-F0-9]{2}){2}'){ + if($Path -match ':'){$Path=$Path -replace '^[^:]+:'} + $Path=[System.Web.HttpUtility]::UrlDecode($Path) + } if (!$ElementId -eq "") { # Use ElementId parameters if (!$Path -eq "") {write-debug("Warning: Path and ElementId parameters are set. Only ElementId is used!")} $drive="/drive" - if ($DriveId -ne "") - { + if ($DriveId -ne "") + { # Named drive $drive="/drives/"+$DriveId } @@ -332,11 +445,11 @@ function Format-ODPathorIdString $tmpString="" foreach ($Sub in $Path.Split("/")) {$tmpString+=$Sub+"/"} $Path=$tmpString - # remove last "/" if exist + # remove last "/" if exist $Path=$Path.TrimEnd("/") # insert drive part of URL - if ($DriveId -eq "") - { + if ($DriveId -eq "") + { # Default drive $Path="/drive/root:"+$Path+":" } @@ -372,12 +485,12 @@ function Get-ODItemProperty Get the default set of metadata for a file or folder (name, size, lastModifiedDateTime, id) Get-ODItemProperty -AccessToken $AuthToken -ElementId 8BADCFF017EAA324!12169 -SelectProperties "" - Get all metadata of a file or folder by element id ("" select all properties) + Get all metadata of a file or folder by element id ("" select all properties) .NOTES Author: Marcel Meurer, marcel.meurer@sepago.de, Twitter: MarcelMeurer #> PARAM( - [Parameter(Mandatory=$True)] + [Parameter(Mandatory=$false)] [string]$AccessToken, [string]$ResourceId="", [string]$Path="/", @@ -385,6 +498,7 @@ function Get-ODItemProperty [string]$SelectProperties="name,size,lastModifiedDateTime,id", [string]$DriveId="" ) + $ProgressPreference="SilentlyContinue" return Get-ODChildItems -AccessToken $AccessToken -ResourceId $ResourceId -Path $Path -ElementId $ElementId -SelectProperties $SelectProperties -DriveId $DriveId -ItemPropertyMode } @@ -416,10 +530,11 @@ function Get-ODChildItems Author: Marcel Meurer, marcel.meurer@sepago.de, Twitter: MarcelMeurer #> PARAM( - [Parameter(Mandatory=$True)] + [Parameter(Mandatory=$false)] [string]$AccessToken, [String]$ResourceId="", [string]$Path="/", + [Parameter(HelpMessage="input folder id")] [string]$ElementId="", [string]$SelectProperties="name,size,lastModifiedDateTime,id", [string]$DriveId="", @@ -430,12 +545,13 @@ function Get-ODChildItems [parameter(DontShow)] [switch]$Loop=$false ) + $ProgressPreference="SilentlyContinue" $ODRootURI=Get-ODRootUri -ResourceId $ResourceId if ($Path.Contains('$skiptoken=') -or $Loop) - { + { # Recursive mode of odata.nextLink detection write-debug("Recursive call") - $rURI=$Path + $rURI=$Path } else { @@ -457,7 +573,7 @@ function Get-ODChildItems } else { - if (!$SearchText -eq "") + if (!$SearchText -eq "") { # Search mode $opt="/view.search?q="+$SearchText+"&select="+$SelectProperties @@ -472,7 +588,7 @@ function Get-ODChildItems } write-debug("Accessing API with GET to "+$rURI) $ResponseObject=Get-ODWebContent -AccessToken $AccessToken -ResourceId $ResourceId -Method GET -rURI $rURI - if ($ResponseObject.PSobject.Properties.name -match "@odata.nextLink") + if ($ResponseObject.PSobject.Properties.name -match "@odata.nextLink") { write-debug("Getting more elements form service (@odata.nextLink is present)") write-debug("LAST: "+$ResponseObject.value.count) @@ -511,23 +627,35 @@ function Search-ODItems .PARAMETER DriveId Specifies the OneDrive drive id. If not set, the default drive is used. .EXAMPLE - Search-ODItems -AccessToken $AuthToken -Path "/My pictures" -SearchText "FolderA" + Search-ODItems -AccessToken $AuthToken -Path "/My pictures" -SearchText "FolderA" + Search-ODItems + Search-ODItems + Search-ODItems + Search-ODItems f -selectproperties 'name,id' + Search-ODItems 'mm' -path '/powershell' + Search-ODItems 'mm' -path '/powershell' -AccessToken $AuthToken Searches for items in a sub folder recursively. Take a look at OneDrives API documentation to see how search (preview) works (file and folder names, in files, …) .NOTES Author: Marcel Meurer, marcel.meurer@sepago.de, Twitter: MarcelMeurer #> PARAM( - [Parameter(Mandatory=$True)] + [Parameter(Mandatory=$false)] [string]$AccessToken, [String]$ResourceId="", - [Parameter(Mandatory=$True)] + [Parameter(Mandatory=$false,Position=0)] [string]$SearchText, + [Parameter(Mandatory=$false,Position=3)] [string]$Path="/", + [Parameter(Mandatory=$false,Position=1)] [string]$ElementId="", + [Parameter(Mandatory=$false,Position=2)] [string]$SelectProperties="name,size,lastModifiedDateTime,id", + [Parameter(Mandatory=$false)] [string]$DriveId="" ) - return Get-ODChildItems -AccessToken $AccessToken -ResourceId $ResourceId -Path $Path -ElementId $ElementId -SelectProperties $SelectProperties -DriveId $DriveId -SearchText $SearchText + $ProgressPreference="SilentlyContinue" + if(!($SearchText)-and!($ElementId)){"请输入一个值:SearchText or ElementId";break} + return Get-ODChildItems -AccessToken $AccessToken -ResourceId $ResourceId -Path $Path -ElementId $ElementId -SelectProperties $SelectProperties -DriveId $DriveId -SearchText $SearchText } function New-ODFolder @@ -554,18 +682,22 @@ function New-ODFolder Author: Marcel Meurer, marcel.meurer@sepago.de, Twitter: MarcelMeurer #> PARAM( - [Parameter(Mandatory=$True)] + [Parameter(Mandatory=$false)] [string]$AccessToken, [String]$ResourceId="", [Parameter(Mandatory=$True)] [string]$FolderName, + [Parameter(Mandatory=$true,ParameterSetName="path")] [string]$Path="/", + [Parameter(Mandatory=$true,ParameterSetName="id")] [string]$ElementId="", [string]$DriveId="" ) + $ProgressPreference="SilentlyContinue" $rURI=Format-ODPathorIdString -path $Path -ElementId $ElementId -DriveId $DriveId $rURI=$rURI+"/children" - return Get-ODWebContent -AccessToken $AccessToken -ResourceId $ResourceId -Method POST -rURI $rURI -Body ('{"name": "'+$FolderName+'","folder": { },"@name.conflictBehavior": "fail"}') + $body=@{name=$FolderName;folder=@{};"@name.conflictBehavior"="fail"}|convertto-json -EscapeHandling EscapeNonAscii + return Get-ODWebContent -AccessToken $AccessToken -ResourceId $ResourceId -Method POST -rURI $rURI -Body $body } function Remove-ODItem @@ -590,21 +722,26 @@ function Remove-ODItem Author: Marcel Meurer, marcel.meurer@sepago.de, Twitter: MarcelMeurer #> PARAM( - [Parameter(Mandatory=$True)] + [Parameter(Mandatory=$false)] [string]$AccessToken, [String]$ResourceId="", + [Parameter(Mandatory=$true,ParameterSetName="path")] [string]$Path="", + [Parameter(Mandatory=$true,ParameterSetName="id")] [string]$ElementId="", [string]$DriveId="" ) - if (($ElementId+$Path) -eq "") + $ProgressPreference="SilentlyContinue" + if (($ElementId+$Path) -eq "") { write-error("Path nor ElementId is set") } else { $rURI=Format-ODPathorIdString -path $Path -ElementId $ElementId -DriveId $DriveId - return Get-ODWebContent -AccessToken $AccessToken -ResourceId $ResourceId -Method DELETE -rURI $rURI + $delete=Get-ODWebContent -AccessToken $AccessToken -ResourceId $ResourceId -Method DELETE -rURI $rURI + if($delete -eq 0){"deleted file: $Path$ElementId"|out-host} + #return } } @@ -633,48 +770,56 @@ function Get-ODItem .NOTES Author: Marcel Meurer, marcel.meurer@sepago.de, Twitter: MarcelMeurer #> + [CmdletBinding()] PARAM( - [Parameter(Mandatory=$True)] + [Parameter(Mandatory=$false)] [string]$AccessToken, [String]$ResourceId="", + [Parameter(Mandatory=$true,ParameterSetName="path")] [string]$Path="", + [Parameter(Mandatory=$true,ParameterSetName="id")] [string]$ElementId="", [string]$DriveId="", [string]$LocalPath="", [string]$LocalFileName ) - if (($ElementId+$Path) -eq "") + if (($ElementId+$Path) -eq "") { write-error("Path nor ElementId is set") } else { + $Download=Get-ODItemProperty -AccessToken $AccessToken -ResourceId $ResourceId -Path $Path -ElementId $ElementId -DriveId $DriveId -SelectProperties "name,@content.downloadUrl,lastModifiedDateTime" + if($Download){ if ($LocalPath -eq "") {$LocalPath=Get-Location} + $LocalPath=resolve-Path ($LocalPath.TrimEnd("\")+"\") + write-verbose "Downloadlink: $($Download.'@content.downloadUrl')" if ($LocalFileName -eq "") { - $SaveTo=$LocalPath.TrimEnd("\")+"\"+$Download.name + $SaveTo=$LocalPath+$Download.name } else { - $SaveTo=$LocalPath.TrimEnd("\")+"\"+$LocalFileName + $SaveTo=$LocalPath+$LocalFileName } try { - [System.Net.WebClient]::WebClient + $client = New-Object System.Net.WebClient $client.DownloadFile($Download."@content.downloadUrl",$SaveTo) $file = Get-Item $saveTo $file.LastWriteTime = $Download.lastModifiedDateTime write-verbose("Download complete") - return 0 + + return (Get-Item $saveTo) } catch { write-error("Download error: "+$_.Exception.Response.StatusCode+"`n"+$_.Exception.Response.StatusDescription) return -1 - } - } + }} + } } function Add-ODItem { @@ -694,35 +839,35 @@ function Add-ODItem .PARAMETER LocalFile Path and file of the local file to be uploaded (C:\data\data.csv). .EXAMPLE - Add-ODItem -AccessToken $AuthToken -Path "/Data/documents/2016" -LocalFile "AzureML with PowerShell.docx" + Add-ODItem -AccessToken $AuthToken -Path "/Data/documents/2016" -LocalFile "AzureML with PowerShell.docx" Upload a file to OneDrive "/data/documents/2016" .NOTES Author: Marcel Meurer, marcel.meurer@sepago.de, Twitter: MarcelMeurer #> PARAM( - [Parameter(Mandatory=$True)] + [Parameter(Mandatory=$false)] [string]$AccessToken, [String]$ResourceId="", - [string]$Path="/", + [string]$Path="", [string]$ElementId="", [string]$DriveId="", - [Parameter(Mandatory=$True)] + [ValidateScript( + { + if (test-path $_ -PathType Leaf ) + { + $true + } + else + { + Throw "file does not exist" + } + })] + [Parameter(Mandatory=$true)] [string]$LocalFile="" ) + if($ElementId -and $Path){throw '"-ElementId" and "-Path"Cannot coexist';break}elseif(!$ElementId){$path='/'} $rURI=Format-ODPathorIdString -path $Path -ElementId $ElementId -DriveId $DriveId - try - { - $spacer="" - if ($ElementId -ne "") {$spacer=":"} - $ODRootURI=Get-ODRootUri -ResourceId $ResourceId - $rURI=(($ODRootURI+$rURI).TrimEnd(":")+$spacer+"/"+[System.IO.Path]::GetFileName($LocalFile)+":/content").Replace("/root/","/root:/") - return $webRequest=Invoke-WebRequest -Method PUT -InFile $LocalFile -Uri $rURI -Header @{ Authorization = "BEARER "+$AccessToken} -ContentType "multipart/form-data" -UseBasicParsing -ErrorAction SilentlyContinue - } - catch - { - write-error("Upload error: "+$_.Exception.Response.StatusCode+"`n"+$_.Exception.Response.StatusDescription) - return -1 - } + getweb -method put -accesstoken $accesstoken -ResourceId $ResourceId -localfile $LocalFile -additem } function Add-ODItemLarge { <# @@ -742,114 +887,135 @@ function Add-ODItemLarge { .PARAMETER LocalFile Path and file of the local file to be uploaded (C:\data\data.csv). .EXAMPLE - Add-ODItem -AccessToken $AuthToken -Path "/Data/documents/2016" -LocalFile "AzureML with PowerShell.docx" + Add-ODItem -AccessToken $AuthToken -Path "/Data/documents/2016" -LocalFile "AzureML with PowerShell.docx" Upload a file to OneDrive "/data/documents/2016" .NOTES Author: Benke Tamás - (funkeninduktor@gmail.com) #> - + [CmdletBinding()] PARAM( - [Parameter(Mandatory=$True)] + [Parameter(Mandatory=$false)] [string]$AccessToken, [String]$ResourceId="", [string]$Path="/", [string]$ElementId="", [string]$DriveId="", - [Parameter(Mandatory=$True)] - [string]$LocalFile="" + [ValidateScript( + { + if (test-path $_ -PathType Leaf ) + { + $true + } + else + { + Throw "file does not exist" + } + })] + [Parameter(Mandatory=$true)] + [string]$LocalFile="", + [int64]$uploadLength=5mb ) - + if($ElementId -and $Path){throw '"-ElementId" and "-Path"Cannot coexist';break} + $LocalFile=Resolve-Path $LocalFile + if($uploadLength -lt 320kb*2){$uploadLength = 5 * 1024 * 1024} + $br=$true + @("$($env:USERNAME)\appdata\local\Temp\","/tmp/")|ForEach-Object{ + if($br -and (test-path $_)){$tmp="${_}one.tmp";$br=$false}} + if(test-path $tmp){$schedule = get-content -path $tmp -raw + + if(test-json $schedule){ + $schedule = $schedule|convertfrom-json + if($schedule."expirationDateTime" -is [datetime]){$time=(new-timespan (get-date) $schedule."expirationDateTime").TotalSeconds + }}} + $rURI=Format-ODPathorIdString -path $Path -ElementId $ElementId -DriveId $DriveId - Try { + write-verbose 'Calculating file hash' + $hash=get-hashvalue -file $LocalFile + + # Begin to construct the real (full) URI $spacer="" if ($ElementId -ne "") {$spacer=":"} - $ODRootURI=Get-ODRootUri -ResourceId $ResourceId - - # Construct the real (full) URI - $rURI=(($ODRootURI+$rURI).TrimEnd(":")+$spacer+"/"+[System.IO.Path]::GetFileName($LocalFile)+":/createUploadSession").Replace("/root/","/root:/") - - # Initialize upload session - $webRequest=Invoke-WebRequest -Method PUT -Uri $rURI -Header @{ Authorization = "BEARER "+$AccessToken} -ContentType "application/json" -UseBasicParsing -ErrorAction SilentlyContinue + + if($null -eq $time -or $time -lt 20){ + if(test-path $tmp){remove-item $tmp -force + $delete=getweb -Method Delete -uri $schedule.uploadUrl -accesstoken $accesstoken -ResourceId $ResourceId + if($delete -eq 0){write-verbose "deleted $($schedule.uploadUrl)"} + }; $time = $null + } + $fd=[IO.FileStream]::new($localfile, [IO.FileMode]::Open) + $totalLength=$fd.length + $ci=[math]::Ceiling($totalLength/$uploadLength) + + if(($schedule.hash -eq $hash.hash -and $schedule.filelength -eq $hash.filelength) -and $time -gt 20){ + $uURL=$schedule.uploadUrl + $getdata=getweb -method get -accesstoken $accesstoken -ResourceId $ResourceId -uri $uurl + write-verbose "getdata: $($getdata.nextExpectedRanges)" + [int64]$startingIndex =if($getdata){$getdata.nextExpectedRanges.split('-')[0]}else{remove-item $tmp -force ;return '获取在线进度出错,删除记录'} + $convertResponse=$schedule + + }else{ + # Initialize upload session + $convertResponse=getweb -method PUT -accesstoken $accesstoken -ResourceId $ResourceId -largelocalfile $localfile -additem # Parse the response JSON (into a holder variable) - $convertResponse = ($webRequest.Content | ConvertFrom-Json) + # Get the uploadUrl from the response (holder variable) $uURL = $convertResponse.uploadUrl - # echo "HERE COMES THE CORRECT uploadUrl: $uURL" - - # Get the full size of the file to upload (bytes) - $totalLength = (Get-Item $LocalFile).length - # echo "Total file size (bytes): $totalLength" - - # Set the upload chunk size (Recommended: 5MB) - $uploadLength = 5 * 1024 * 1024; # == 5242880 byte == 5MB. - # echo "Size of upload fragments (bytes): $uploadLength" # == 5242880 - + $convertResponse|add-member @{LocalFile=$LocalFile;hash=$hash.hash;filelength=$hash.filelength} + if($ci -gt 1){$convertResponse |convertto-json|set-content -path $tmp} # Set the starting byte index of the upload (i. e.: the index of the first byte of the file to upload) $startingIndex = 0 - - # Start an endless cycle to run until the last chunk of the file is uploaded (after that, BREAK out of the cycle) - while($True){ - # If startingIndex (= the index of the starting byte) is greater than, or equal to totalLength (= the total length of the file), stop execution, so BREAK out of the cycle - if( $startingIndex -ge $totalLength ){ - break - } - - # Otherwise: set the suitable indices (variables) - - # (startingIndex remains as it was!) - - # Set the size of the chunk to upload - # The remaining length of the file (to be uploaded) - $remainingLength = $($totalLength-$startingIndex) - # If remainingLength is smaller than the normal upload length (defined above as uploadLength), then the new uploadLength will be the remainingLength (self-evidently, only for the last upload chunk) - if( $remainingLength -lt $uploadLength ){ - $uploadLength = $remainingLength - } - # Set the new starting index (just for the next iteration!) - $newStartingIndex = $($startingIndex+$uploadLength) - # Get the ending index (by means of newStartingIndex) - $endingIndex = $($newStartingIndex-1) - - # Get the bytes to upload into a byte array (using properly re-initialized variables) - $buf = new-object byte[] $uploadLength - $fs = new-object IO.FileStream($LocalFile, [IO.FileMode]::Open) - $reader = new-object IO.BinaryReader($fs) - $reader.BaseStream.Seek($startingIndex,"Begin") | out-null - $reader.Read($buf, 0, $uploadLength)| out-null - $reader.Close() - # echo "Chunk size is: $($buf.count)" - - # Upoad the actual file chunk (byte array) to the actual upload session. - # Some aspects of the chunk upload: - # We don't have to authenticate for the chunk uploads, since the uploadUrl contains the upload session's authentication data as well. - # We above calculated the length, and starting and ending byte indices of the actual chunk, and the total size of the (entire) file. These should be set into the upload's PUT request headers. - # If the upload session is alive, every file chunk (including the last one) should be uploaded with the same command syntax. - # If the last chunk was uploaded, the file is automatically created (and the upload session is closed). - # The (default) length of an upload session is about 15 minutes! - - # Set the headers for the actual file chunk's PUT request (by means of the above preset variables) - $actHeaders=@{"Content-Length"="$uploadLength"; "Content-Range"="bytes $startingIndex-$endingIndex/$totalLength"}; - - # Execute the PUT request (upload file chunk) - write-debug("Uploading chunk of bytes. Progress: "+$endingIndex/$totalLength*100+" %") - $uploadResponse=Invoke-WebRequest -Method PUT -Uri $uURL -Headers $actHeaders -Body $buf -UseBasicParsing -ErrorAction SilentlyContinue - - # startingIndex should be incremented (with the size of the actually uploaded file chunk) for the next iteration. - # (Since the new value for startingIndex was preset above, as newStartingIndex, here we just have to overwrite startingIndex with it!) - $startingIndex = $newStartingIndex } - # The upload is done! - + +$wc=New-Object System.Net.WebClient +$start=get-date +while(![String]::IsNullOrEmpty($startingIndex)){ +$seek=$fd.seek($startingIndex,'begin') +$uploadLength=[math]::Min($uploadLength,$totalLength-$startingIndex ) +$buf=[byte[]]::new($uploadLength) +$read=$fd.Read($buf,0,$uploadLength) + +$endingIndex=$startingIndex+$uploadLength-1 +$object=[PScustomobject]@{ +'start'=yunsuan $startingIndex +'end'=yunsuan ($endingIndex+1) +'totalLength'=yunsuan $totalLength +'length'=yunsuan $uploadLength +#'seek'=yunsuan $seek +ExpectedRanges=$uploadresponse.nextExpectedRanges +#read=$read +次数=$_ +#buf=$buf.length #[$uploadLength] +#localfile=$localfile +} + +Write-Verbose ($object | Format-Table | Out-String) +$info="$([int64](($totalLength-$startingIndex)/1024))k/$([int64]($totalLength/1024))k:" +write-debug $info + +$progress=[int64]($startingIndex/$totalLength*100) + +Write-Progress -Activity "File uploading:$LocalFile" -Status "$progress% Complete $info" -PercentComplete $progress +$wc.headers.set("Content-Length",$uploadLength) +$wc.headers.set("Content-Range","bytes $startingIndex-$endingIndex/$totalLength") +try{ +[System.Text.Encoding]::ASCII.GetString($wc.UploadData($uurl,'PUT',$buf)) |convertfrom-json|set-variable uploadresponse -PassThru |ForEach-Object{$json=$_.value;'nextExpectedRanges','expirationDateTime'|ForEach-Object{$convertResponse.$_=$json.$_};$convertResponse}|convertto-json|ForEach-Object{if($ci -gt 1){set-content -value $_ -path $tmp}} +}catch{ +write-warning $_.Exception.Message +write-warning 'Will try again' +} +try{ +$startingIndex = [int64]$uploadResponse.nextExpectedRanges.split('-')[0] +}catch{ +remove-variable startingIndex -force +} + +} +$fd.Dispose() # At the end of the upload, write out the last response, which should be a confirmation message: "HTTP/1.1 201 Created" write-debug("Upload complete") - return ($uploadResponse.Content | ConvertFrom-Json) - } - Catch { - write-error("Upload error: "+$_.Exception.Response.StatusCode+"`n"+$_.Exception.Response.StatusDescription) - return -1 - } + return $uploadResponse } function Move-ODItem { @@ -875,35 +1041,40 @@ function Move-ODItem Moves and renames a file in one step Move-ODItem -AccessToken $at -path "/Notes.txt" -NewName "_Notes.txt" # Rename a file - - Move-ODItem -AccessToken $at -path "/Notes.txt" -TargetPath "/x" # Move a file + + Move-ODItem -AccessToken $at -path "/Notes.txt" -TargetPath "/x" -verbose # Move a file + Move-ODItem -path /qq/gh.json -TargetPath :: -verbose + Move to the root directory .NOTES Author: Marcel Meurer, marcel.meurer@sepago.de, Twitter: MarcelMeurer #> PARAM( - [Parameter(Mandatory=$True)] + [Parameter(Mandatory=$false)] [string]$AccessToken, [String]$ResourceId="", + [Parameter(parametersetname='path')] [string]$Path="", + [Parameter(parametersetname='ElementId')] [string]$ElementId="", [string]$DriveId="", [string]$TargetPath="", + [string]$Targetid="", [string]$NewName="" ) - if (($ElementId+$Path) -eq "") + if (($ElementId+$Path) -eq "") { write-error("Path nor ElementId is set") } else { - if (($TargetPath+$NewName) -eq "") + if (($TargetPath+$NewName+$Targetid) -eq "") { write-error("TargetPath nor NewName is set") } else - { + { $body='{' - if (!$NewName -eq "") + if (!$NewName -eq "") { $body=$body+'"name": "'+$NewName+'"' If (!$TargetPath -eq "") @@ -911,14 +1082,241 @@ function Move-ODItem $body=$body+',' } } - if (!$TargetPath -eq "") + if (!$TargetPath -eq "") { - $rTURI=Format-ODPathorIdString -path $TargetPath -DriveId $DriveId + $rTURI=Format-ODPathorIdString -path $TargetPath -DriveId $DriveId #[System.Web.HttpUtility]::UrlEncode( + $rTURI=$rTURI -replace ':$' $body=$body+'"parentReference" : {"path": "'+$rTURI+'"}' } + if (!$Targetid -eq "") + { + $body=$body+'"parentReference" : {"id": "'+$Targetid+'"}' + } $body=$body+'}' - $rURI=Format-ODPathorIdString -path $Path -ElementId $ElementId -DriveId $DriveId + $body + $rURI=(Format-ODPathorIdString -path $Path -ElementId $ElementId -DriveId $DriveId).TrimEnd(':') return Get-ODWebContent -AccessToken $AccessToken -ResourceId $ResourceId -Method PATCH -rURI $rURI -Body $body } } -} \ No newline at end of file +} +function Get-ODShareLinkDownload + <# + .DESCRIPTION + Download a shared file + .PARAMETER URL + onedrive.live.com Share links + .PARAMETER path + + .EXAMPLE + get-ODShareLinkDownload -URL https://1drv.ms/f/s!AtftJLuuzIqngqg598UpNi1x5YJ8bQ + Download a file + get-ODShareLinkDownload -URL xxx + get-ODShareLinkDownload -URL xxx -path c:\d\d\ + .NOTES + Avoid downloading large files + The application for OneDrive 4 Business needs "Read items in all site collections" on application level (API: Office 365 SharePoint Online) + Author: Marcel Meurer, marcel.meurer@sepago.de, Twitter: MarcelMeurer + #> + {PAram( + [Parameter(Mandatory=$true,Position=0)] + [string]$uri, + [Parameter(Mandatory=$false,Position=1)] + [string]$path='./') + if(-not(Test-Path $path)){write-host -ForegroundColor DarkCyan 'Tips:error path';break} + if($path -match '[^/]$'){ + $path= (resolve-path -path $path).path+"/"} +$ProgressPreference= "SilentlyContinue" + +function Folder-downloads { +PAram([string]$URL,[string]$path='./') +[array]$URL=$URL +$path=(resolve-path -path $path).path +$data=@() +[array]$path1=$path +$yuan='https://storage.live.com/items/' +$folderID=@() +do { +if ($null -ne $folderID[0] -and $folderID[0] -ne $replace){ +[string]$replace=$folderID[0] +$url=@() +[array]$folder=$path1|select-object -Skip $folder.length +$path1=@() +for ($i=0;$i -lt $folder.length;$i++) { +for ($x=0;$X -lt $folderName.length;$x++) { +$path1+=$folder[$i]+$folderName[$x]+'/' +$itempath=$folder[$i]+$folderName[$x]+"/" +$null=New-Item -path "$itempath" -itemtype Directory -force}} +$folderID|ForEach-Object{$url+="$yuan$_$key"} +Remove-variable folderName,folderID -force} +for ($x=0;$x -lt $URL.length;$x++){ +$xml=Invoke-RestMethod $URL[$x] +$dd= [System.Text.Encoding]::UTF8.GetString([System.Text.Encoding]::GetEncoding(28591).GetBytes($xml)) +$key='?'+ ($URL[$x] |select-string -pattern 'authkey.*$').matches.value +$dd=$([XML]$($dd -replace '^[^<]+')).Folder.Items +[array]$ResourceID=$dd.Document.ResourceID +[array]$RelationshipName=$dd.Document.RelationshipName +for ($i=0;$I -lt $ResourceID.length;$i++){ +$data+=[PScustomobject]@{ +ResourceID=$ResourceID[$i] +RelationshipName=$RelationshipName[$i] +path= $path1[$x]+$RelationshipName[$i] +url=($yuan+$ResourceID[$i]+$key)}} +[array]$folderID=$dd.folder.ResourceID +[array]$folderName=$dd.folder.RelationshipName} +} until ($null -eq $folderID) +$script=@() +For ( $x=0; $x -lt $data.length;$x++){ +$path=$data.path[$x] +$URL=$data.url[$x] +$script+="iwr '$URL' -o '$path'"} +if ($script -is [array] -and $script.length -gt 5){ +runspace0 $script +}elseif($script -is [string]){Invoke-Expression $script}else{ +for ($x=0;$x -lt $script.length;$x++){ +Invoke-Expression $script[$x]}} +write-host "文件数量:"$ResourceID.count -ForegroundColor Blue|out-host +$data} + +if ($uri -notmatch 'onedrive|skydrive|storage'){ + $link=Invoke-WebRequest $uri -MaximumRedirection 0 -SkipHttpErrorCheck -ErrorAction Ignore + $link=$link.headers.location +}else{$link=$uri} +if ($link -match 'ithint\=folder'){ + $link= $link -replace '^(.*?)(?:onedrive|skydrive)(\..*)?(?:redir|download)\?resid\=(.*?\d)(\&a.*)$','$1storage$2items/$3?$4' + [PScustomobject]@{链接地址=$link}|format-table -wrap + Folder-downloads -URL $link -path $path +}else{ + #$link -replace '^(.*?)(?:onedrive|skydrive)(\..*)?(?:redir|download)(.*)$','$1skydrive$2download$3'|out-host + #$link -replace '^(.*?)(?:onedrive|skydrive)(\..*)?(?:redir|download)\?resid\=(.*?\d)(\&a.*)$','$1storage$2items/$3?$4'|out-host + $link= $link -replace '^(.*?)(?:onedrive|skydrive)(\..*)?(?:redir|download)(.*)$','$1skydrive$2download$3' + #$link=iwr $uri -MaximumRedirection 0 -SkipHttpErrorCheck -ErrorAction Ignore + [PScustomobject]@{链接地址=$link}|format-table -wrap + $data=Invoke-WebRequest "$link" + $replace=$data.headers.'Content-Disposition' -replace '^.*?(?=[^ ''"]+$)' + $name=[System.Web.HttpUtility]::UrlDecode($replace) + set-content -value $data -path "$path$name" + [PScustomobject]@{ + name=$name + path=$path + URL=$link +}}} + +function Runspace0{ +param($ScriptBlock) +$throttleLimit = 8 +$SessionState = [system.management.automation.runspaces.initialsessionstate]::CreateDefault() +$Pool = [runspacefactory]::CreateRunspacePool(1, $throttleLimit, $SessionState, $Host) +$Pool.Open() +if ($ScriptBlock -is [string]){[array]$ScriptBlock=$ScriptBlock} +$threads = @() +$handles = for ($x = 0; $x -lt $ScriptBlock.length; $x++) { +$fg=$ScriptBlock[$x] +$scriptblock1=@" +param(`$id) +`$ErrorActionPreference='SilentlyContinue'; +`$WarningPreference='SilentlyContinue'; +`$ProgressPreference='SilentlyContinue'; +`$code=($fg) +[PScustomobject]@{id=`$id;code=`$code} +"@ + $powershell = [powershell]::Create().AddScript($scriptblock1).AddArgument($x) + $powershell.RunspacePool = $Pool + $powershell.BeginInvoke() + $threads += $powershell} +if ($handles -is [string]){[array]$handles=$handles} +$ss=@() +do { +$done = $true +# ($handles -ne $null).length +for ($x=0;$X -lt $handles.length;$x++){ +$bi=$handles[$x].IsCompleted -like 'true' +if ($bi){ +$ss=$ss += $threads[$x].EndInvoke($handles[$x]) +$threads[$x].Dispose() +$handles[$x]=$null +$threads[$x]=$null}} +if ($null -ne $handles.IsCompleted){$done = $false} +if (-not $done) { Start-Sleep -Milliseconds 900 } +} until ($done) +($ss |sort-object -Property id).code +} + + + +function getweb { +[CmdletBinding()] +param($method,$uri,$body,$accesstoken,$ResourceId,$LocalFile,$largelocalfile,[switch]$additem) +if($LocalFile -and $largelocalfile){write-error '-LocalFile and -largelocalfile 不能共存';break} +if($largelocalfile){$file=@($largeLocalFile,":/createUploadSession")}elseif($localfile){$file=@($LocalFile,":/content")} +if (!($Authentication)){$Global:Authentication = New-Object PSObject} + if($AccessToken -and ($AccessToken -ne $Authentication.access_token)){ + switch ($null -eq $Authentication.ResourceId) { + true {$Authentication | add-member Noteproperty 'access_token' ($AccessToken)} + false {$Authentication.access_token=$AccessToken}}} + if($ResourceId -and ($ResourceId -ne $Authentication.ResourceId)){ + switch ($null -eq $Authentication.ResourceId) { + false {$Authentication.ResourceId=$ResourceId} + true {$Authentication | add-member Noteproperty 'ResourceId' ($ResourceId)}}} + + $code=@('invalid_token',"The caller is not authenticated.","Authentication failed") + do{ + $ODRootURI=Get-ODRootUri -ResourceId $ResourceId + if($uri -match '^http') {$ruri1=$uri}elseif($additem){ + $spacer="" + if ($ElementId -ne "") {$spacer=":"} + $rURI1=(($ODRootURI+$rURI).TrimEnd(":")+$spacer+"/"+[System.IO.Path]::GetFileName($File[0])+$File[1]).Replace("/root/","/root:/") + }else{$ruri1=($ODRootURI+$rURI)} + if($messq){remove-variable messq -force} + Try{ + if($LocalFile){ + $webRequest=Invoke-WebRequest -Method $Method -InFile $LocalFile -Uri $rURI1 -Header @{ Authorization = "BEARER "+$AccessToken} -ContentType "multipart/form-data" -UseBasicParsing + }else{ + $webRequest=Invoke-WebRequest -Method $Method -Uri $ruri1 -Header @{ Authorization = "BEARER "+$AccessToken} -ContentType "application/json" -Body $Body -UseBasicParsing + } + } + Catch { + #write-verbose ("Upload error: "+$_.Exception.Response.StatusCode+"`n"+ $_.Exception.Response.StatusDescription) + #return -1 + $mess=($_.Exception.response.Headers|Where-Object{$_.key -like 'WWW-Authenticate'}).value + if($mess){$mess=$mess -replace '(^|,)[ ]*([^=]+)=("[^"]+")','$1"$2":$3' -replace '^(.*)$','{$1}' |convertfrom-json;write-verbose ($mess|format-table |out-string)} + if($_.ErrorDetails.Message){ $messq=($_.ErrorDetails.Message|convertfrom-json).error.message;write-verbose ($messq|format-table|out-string)} + if($_.Exception.Message){write-verbose $_.Exception.Message} + if($code -contains $messq){#$mess.error + splash + $AccessToken=$Authentication.access_token + $ResourceId=$Authentication.resourceid + }} + }until($code -notcontains $messq) #$mess.error + switch ($webRequest.StatusCode) + { + 200 + { + if (!$BinaryMode) {$responseObject = ConvertFrom-Json $webRequest.Content} + return $responseObject + } + 201 + { + write-debug("Success: "+$webRequest.StatusCode+" - "+$webRequest.StatusDescription) + if (!$BinaryMode) {$responseObject = ConvertFrom-Json $webRequest.Content} + return $responseObject + } + 204 + { + write-debug("Success: "+$webRequest.StatusCode+" - "+$webRequest.StatusDescription+" (item deleted)") + $responseObject = "0" + return $responseObject + } + #default {write-warning("Cannot access the api. Webrequest return code is: "+$webRequest.StatusCode+"`n"+$webRequest.StatusDescription)} + } +} + +function yunsuan {param($data) +if ($data -ge 1GB) +{'{0:F0}GB' -f ($data / 1GB)} +elseif ($data -ge 1MB) +{'{0:F0}MB' -f ($data / 1MB)} +elseif ($data -ge 1KB) +{'{0:F0}KB' -f ($data / 1KB)} +else +{'{0}bytes' -f $data} +}