API Script node-docx-to-page not working #3301

Closed
opened 2026-02-05 06:18:11 +03:00 by OVERLORD · 9 comments
Owner

Originally created by @mschoon85 on GitHub (Oct 24, 2022).

Attempted Debugging

  • I have read the debugging page

Searched GitHub Issues

  • I have searched GitHub for the issue.

Describe the Scenario

Hello,

I'm trying to use the node-docx-to-page API script to import Word documents into Bookstack, as there is no way to do this within the GUI.

On the page https://github.com/BookStackApp/api-scripts/tree/main/node-docx-to-page the first step fails (npm install):

image

I cannot proceed with importing Word documents. Also we would like to see an option within the Bookstack GUI to import Word documents (.doc and/or .docx) as our current Knowledge Base exists out of hundreds of word documents.

Kind Regards and thanks in advance,

Michel

Exact BookStack Version

22.09.1

Log Content

0 verbose cli D:\Program Files\nodejs\node.exe C:\Users\xx\AppData\Roaming\npm\node_modules\npm\bin\npm-cli.js
1 info using npm@8.19.1
2 info using node@v16.17.0
3 timing npm:load:whichnode Completed in 1ms
4 timing config:load:defaults Completed in 2ms
5 timing config:load:file:C:\Users\xx\AppData\Roaming\npm\node_modules\npm\npmrc Completed in 4ms
6 timing config:load:builtin Completed in 4ms
7 timing config:load:cli Completed in 2ms
8 timing config:load:env Completed in 0ms
9 timing config:load:file:D:\Docx to Bookstack\.npmrc Completed in 0ms
10 timing config:load:project Completed in 2ms
11 timing config:load:file:C:\Users\xx\.npmrc Completed in 0ms
12 timing config:load:user Completed in 0ms
13 timing config:load:file:C:\Users\xx\AppData\Roaming\npm\etc\npmrc Completed in 0ms
14 timing config:load:global Completed in 1ms
15 timing config:load:validate Completed in 0ms
16 timing config:load:credentials Completed in 1ms
17 timing config:load:setEnvs Completed in 1ms
18 timing config:load Completed in 14ms
19 timing npm:load:configload Completed in 14ms
20 timing npm:load:mkdirpcache Completed in 1ms
21 timing npm:load:mkdirplogs Completed in 1ms
22 verbose title npm install
23 verbose argv "install"
24 timing npm:load:setTitle Completed in 2ms
25 timing config:load:flatten Completed in 6ms
26 timing npm:load:display Completed in 9ms
27 verbose logfile logs-max:10 dir:C:\Users\xx\AppData\Local\npm-cache\_logs
28 verbose logfile C:\Users\xx\AppData\Local\npm-cache\_logs\2022-10-24T10_47_35_991Z-debug-0.log
29 timing npm:load:logFile Completed in 8ms
30 timing npm:load:timers Completed in 0ms
31 timing npm:load:configScope Completed in 0ms
32 timing npm:load Completed in 36ms
33 timing arborist:ctor Completed in 1ms
34 silly logfile start cleaning logs, removing 1 files
35 silly logfile done cleaning log files
36 timing idealTree Completed in 4ms
37 timing command:install Completed in 32ms
38 verbose stack JSONParseError: Unexpected token "<" (0x3C) in JSON at position 0 while parsing near "<!DOCTYPE html>\n<htm..."
38 verbose stack     at C:\Users\xx\AppData\Roaming\npm\node_modules\npm\node_modules\read-package-json-fast\index.js:11:61
38 verbose stack     at async Arborist.buildIdealTree (C:\Users\xx\AppData\Roaming\npm\node_modules\npm\node_modules\@npmcli\arborist\lib\arborist\build-ideal-tree.js:208:7)
38 verbose stack     at async Promise.all (index 1)
38 verbose stack     at async Arborist.reify (C:\Users\xx\AppData\Roaming\npm\node_modules\npm\node_modules\@npmcli\arborist\lib\arborist\reify.js:153:5)
38 verbose stack     at async Install.exec (C:\Users\xx\AppData\Roaming\npm\node_modules\npm\lib\commands\install.js:145:5)
38 verbose stack     at async module.exports (C:\Users\xx\AppData\Roaming\npm\node_modules\npm\lib\cli.js:78:5)
39 verbose cwd D:\Docx to Bookstack
40 verbose Windows_NT 10.0.20348
41 verbose node v16.17.0
42 verbose npm  v8.19.1
43 error code EJSONPARSE
44 error path D:\Docx to Bookstack/package.json
45 error JSON.parse Unexpected token "<" (0x3C) in JSON at position 0 while parsing near "<!DOCTYPE html>\n<htm..."
46 error JSON.parse Failed to parse JSON data.
46 error JSON.parse Note: package.json must be actual JSON, not just JavaScript.
47 verbose exit 1
48 timing npm Completed in 241ms
49 verbose unfinished npm timer reify 1666608456196
50 verbose unfinished npm timer reify:loadTrees 1666608456219
51 verbose unfinished npm timer idealTree:init 1666608456220
52 verbose code 1
53 error A complete log of this run can be found in:
53 error     C:\Users\xx\AppData\Local\npm-cache\_logs\2022-10-24T10_47_35_991Z-debug-0.log

PHP Version

8.1.11

Hosting Environment

Windows Server 2022

Originally created by @mschoon85 on GitHub (Oct 24, 2022). ### Attempted Debugging - [X] I have read the debugging page ### Searched GitHub Issues - [X] I have searched GitHub for the issue. ### Describe the Scenario Hello, I'm trying to use the node-docx-to-page API script to import Word documents into Bookstack, as there is no way to do this within the GUI. On the page https://github.com/BookStackApp/api-scripts/tree/main/node-docx-to-page the first step fails (npm install): ![image](https://user-images.githubusercontent.com/96066244/197509651-a7dedba5-2258-49a4-8ae6-ffb90924081f.png) I cannot proceed with importing Word documents. Also we would like to see an option within the Bookstack GUI to import Word documents (.doc and/or .docx) as our current Knowledge Base exists out of hundreds of word documents. Kind Regards and thanks in advance, Michel ### Exact BookStack Version 22.09.1 ### Log Content <details> ``` 0 verbose cli D:\Program Files\nodejs\node.exe C:\Users\xx\AppData\Roaming\npm\node_modules\npm\bin\npm-cli.js 1 info using npm@8.19.1 2 info using node@v16.17.0 3 timing npm:load:whichnode Completed in 1ms 4 timing config:load:defaults Completed in 2ms 5 timing config:load:file:C:\Users\xx\AppData\Roaming\npm\node_modules\npm\npmrc Completed in 4ms 6 timing config:load:builtin Completed in 4ms 7 timing config:load:cli Completed in 2ms 8 timing config:load:env Completed in 0ms 9 timing config:load:file:D:\Docx to Bookstack\.npmrc Completed in 0ms 10 timing config:load:project Completed in 2ms 11 timing config:load:file:C:\Users\xx\.npmrc Completed in 0ms 12 timing config:load:user Completed in 0ms 13 timing config:load:file:C:\Users\xx\AppData\Roaming\npm\etc\npmrc Completed in 0ms 14 timing config:load:global Completed in 1ms 15 timing config:load:validate Completed in 0ms 16 timing config:load:credentials Completed in 1ms 17 timing config:load:setEnvs Completed in 1ms 18 timing config:load Completed in 14ms 19 timing npm:load:configload Completed in 14ms 20 timing npm:load:mkdirpcache Completed in 1ms 21 timing npm:load:mkdirplogs Completed in 1ms 22 verbose title npm install 23 verbose argv "install" 24 timing npm:load:setTitle Completed in 2ms 25 timing config:load:flatten Completed in 6ms 26 timing npm:load:display Completed in 9ms 27 verbose logfile logs-max:10 dir:C:\Users\xx\AppData\Local\npm-cache\_logs 28 verbose logfile C:\Users\xx\AppData\Local\npm-cache\_logs\2022-10-24T10_47_35_991Z-debug-0.log 29 timing npm:load:logFile Completed in 8ms 30 timing npm:load:timers Completed in 0ms 31 timing npm:load:configScope Completed in 0ms 32 timing npm:load Completed in 36ms 33 timing arborist:ctor Completed in 1ms 34 silly logfile start cleaning logs, removing 1 files 35 silly logfile done cleaning log files 36 timing idealTree Completed in 4ms 37 timing command:install Completed in 32ms 38 verbose stack JSONParseError: Unexpected token "<" (0x3C) in JSON at position 0 while parsing near "<!DOCTYPE html>\n<htm..." 38 verbose stack at C:\Users\xx\AppData\Roaming\npm\node_modules\npm\node_modules\read-package-json-fast\index.js:11:61 38 verbose stack at async Arborist.buildIdealTree (C:\Users\xx\AppData\Roaming\npm\node_modules\npm\node_modules\@npmcli\arborist\lib\arborist\build-ideal-tree.js:208:7) 38 verbose stack at async Promise.all (index 1) 38 verbose stack at async Arborist.reify (C:\Users\xx\AppData\Roaming\npm\node_modules\npm\node_modules\@npmcli\arborist\lib\arborist\reify.js:153:5) 38 verbose stack at async Install.exec (C:\Users\xx\AppData\Roaming\npm\node_modules\npm\lib\commands\install.js:145:5) 38 verbose stack at async module.exports (C:\Users\xx\AppData\Roaming\npm\node_modules\npm\lib\cli.js:78:5) 39 verbose cwd D:\Docx to Bookstack 40 verbose Windows_NT 10.0.20348 41 verbose node v16.17.0 42 verbose npm v8.19.1 43 error code EJSONPARSE 44 error path D:\Docx to Bookstack/package.json 45 error JSON.parse Unexpected token "<" (0x3C) in JSON at position 0 while parsing near "<!DOCTYPE html>\n<htm..." 46 error JSON.parse Failed to parse JSON data. 46 error JSON.parse Note: package.json must be actual JSON, not just JavaScript. 47 verbose exit 1 48 timing npm Completed in 241ms 49 verbose unfinished npm timer reify 1666608456196 50 verbose unfinished npm timer reify:loadTrees 1666608456219 51 verbose unfinished npm timer idealTree:init 1666608456220 52 verbose code 1 53 error A complete log of this run can be found in: 53 error C:\Users\xx\AppData\Local\npm-cache\_logs\2022-10-24T10_47_35_991Z-debug-0.log ``` </details> ### PHP Version 8.1.11 ### Hosting Environment Windows Server 2022
OVERLORD added the 🐕 Support label 2026-02-05 06:18:11 +03:00
Author
Owner

@ssddanbrown commented on GitHub (Oct 24, 2022):

Hi @mschoon85,
Please check you have downloaded the script files properly.
The error seems to indicate the package.json file contains HTML content which is not as per the node-docx-to-page files.

You can download all our api scripts as a zip via this link, then extract then then use just the node-docx-to-page directory.

@ssddanbrown commented on GitHub (Oct 24, 2022): Hi @mschoon85, Please check you have downloaded the script files properly. The error seems to indicate the `package.json` file contains HTML content which is not as per the `node-docx-to-page` files. You can download all our api scripts [as a zip via this link](https://github.com/BookStackApp/api-scripts/archive/refs/heads/main.zip), then extract then then use just the `node-docx-to-page` directory.
Author
Owner

@mschoon85 commented on GitHub (Oct 24, 2022):

Hi @ssddanbrown ,

Downloading the zip file did the trick. Thanks for replying so fast!

@mschoon85 commented on GitHub (Oct 24, 2022): Hi @ssddanbrown , Downloading the zip file did the trick. Thanks for replying so fast!
Author
Owner

@mschoon85 commented on GitHub (Oct 24, 2022):

@ssddanbrown Unfortunately I ran into another problem:

D:\API scripts\node-docx-to-page>node index.js testdocument.docx testpage

Error: unable to verify the first certificate
    at TLSSocket.onConnectSecure (node:_tls_wrap:1535:34)
    at TLSSocket.emit (node:events:513:28)
    at TLSSocket._finishInit (node:_tls_wrap:949:8)
    at TLSWrap.ssl.onhandshakedone (node:_tls_wrap:730:12) {
  code: 'UNABLE_TO_VERIFY_LEAF_SIGNATURE',
  config: {
    url: '/books?filter[slug]=testpage',
    method: 'get',
    headers: {
      Accept: 'application/json, text/plain, */*',
      Authorization: 'Token puN1AY6zEQ62CX0gNo3mTHoLW4O5WxYW:zojyPKBwFl5WfVssHQEV3g2UxjnclFVQ',
      'User-Agent': 'axios/0.21.4'
    },
    baseURL: 'https://URL.com/api/',
    transformRequest: [ [Function: transformRequest] ],
    transformResponse: [ [Function: transformResponse] ],
    timeout: 5000,
    adapter: [Function: httpAdapter],
    xsrfCookieName: 'XSRF-TOKEN',
    xsrfHeaderName: 'X-XSRF-TOKEN',
    maxContentLength: -1,
    maxBodyLength: -1,
    validateStatus: [Function: validateStatus],
    transitional: {
      silentJSONParsing: true,
      forcedJSONParsing: true,
      clarifyTimeoutError: false
    },
    data: undefined
  },
  request: <ref *1> Writable {
    _writableState: WritableState {
      objectMode: false,
      highWaterMark: 16384,
      finalCalled: false,
      needDrain: false,
      ending: false,
      ended: false,
      finished: false,
      destroyed: false,
      decodeStrings: true,
      defaultEncoding: 'utf8',
      length: 0,
      writing: false,
      corked: 0,
      sync: true,
      bufferProcessing: false,
      onwrite: [Function: bound onwrite],
      writecb: null,
      writelen: 0,
      afterWriteTickInfo: null,
      buffered: [],
      bufferedIndex: 0,
      allBuffers: true,
      allNoop: true,
      pendingcb: 0,
      constructed: true,
      prefinished: false,
      errorEmitted: false,
      emitClose: true,
      autoDestroy: true,
      errored: null,
      closed: false,
      closeEmitted: false,
      [Symbol(kOnFinished)]: []
    },
    _events: [Object: null prototype] {
      response: [Function: handleResponse],
      error: [Function: handleRequestError],
      socket: [Function: destroyOnTimeout]
    },
    _eventsCount: 3,
    _maxListeners: undefined,
    _options: {
      maxRedirects: 21,
      maxBodyLength: 10485760,
      protocol: 'https:',
      path: '/api/books?filter[slug]=testpage',
      method: 'GET',
      headers: [Object],
      agent: undefined,
      agents: [Object],
      auth: undefined,
      hostname: 'URL.com',
      port: null,
      nativeProtocols: [Object],
      pathname: '/api/books',
      search: '?filter[slug]=testpage'
    },
    _ended: true,
    _ending: true,
    _redirectCount: 0,
    _redirects: [],
    _requestBodyLength: 0,
    _requestBodyBuffers: [],
    _onNativeResponse: [Function (anonymous)],
    _currentRequest: ClientRequest {
      _events: [Object: null prototype],
      _eventsCount: 7,
      _maxListeners: undefined,
      outputData: [],
      outputSize: 0,
      writable: true,
      destroyed: false,
      _last: true,
      chunkedEncoding: false,
      shouldKeepAlive: false,
      maxRequestsOnConnectionReached: false,
      _defaultKeepAlive: true,
      useChunkedEncodingByDefault: false,
      sendDate: false,
      _removedConnection: false,
      _removedContLen: false,
      _removedTE: false,
      _contentLength: 0,
      _hasBody: true,
      _trailer: '',
      finished: true,
      _headerSent: true,
      _closed: false,
      socket: [TLSSocket],
      _header: 'GET /api/books?filter[slug]=testpage HTTP/1.1\r\n' +
        'Accept: application/json, text/plain, */*\r\n' +
        'Authorization: Token puN1AY6zEQ62CX0gNo3mTHoLW4O5WxYW:zojyPKBwFl5WfVssHQEV3g2UxjnclFVQ\r\n' +
        'User-Agent: axios/0.21.4\r\n' +
        'Host: URL.com\r\n' +
        'Connection: close\r\n' +
        '\r\n',
      _keepAliveTimeout: 0,
      _onPendingData: [Function: nop],
      agent: [Agent],
      socketPath: undefined,
      method: 'GET',
      maxHeaderSize: undefined,
      insecureHTTPParser: undefined,
      path: '/api/books?filter[slug]=testpage',
      _ended: false,
      res: null,
      aborted: false,
      timeoutCb: null,
      upgradeOrConnect: false,
      parser: null,
      maxHeadersCount: null,
      reusedSocket: false,
      host: 'URL.com',
      protocol: 'https:',
      _redirectable: [Circular *1],
      [Symbol(kCapture)]: false,
      [Symbol(kNeedDrain)]: false,
      [Symbol(corked)]: 0,
      [Symbol(kOutHeaders)]: [Object: null prototype],
      [Symbol(kUniqueHeaders)]: null
    },
    _currentUrl: 'URL.com/api/books?filter[slug]=testpage',
    _timeout: null,
    [Symbol(kCapture)]: false
  },
  response: undefined,
  isAxiosError: true,
  toJSON: [Function: toJSON]
}
@mschoon85 commented on GitHub (Oct 24, 2022): @ssddanbrown Unfortunately I ran into another problem: D:\API scripts\node-docx-to-page>node index.js testdocument.docx testpage <details> ``` Error: unable to verify the first certificate at TLSSocket.onConnectSecure (node:_tls_wrap:1535:34) at TLSSocket.emit (node:events:513:28) at TLSSocket._finishInit (node:_tls_wrap:949:8) at TLSWrap.ssl.onhandshakedone (node:_tls_wrap:730:12) { code: 'UNABLE_TO_VERIFY_LEAF_SIGNATURE', config: { url: '/books?filter[slug]=testpage', method: 'get', headers: { Accept: 'application/json, text/plain, */*', Authorization: 'Token puN1AY6zEQ62CX0gNo3mTHoLW4O5WxYW:zojyPKBwFl5WfVssHQEV3g2UxjnclFVQ', 'User-Agent': 'axios/0.21.4' }, baseURL: 'https://URL.com/api/', transformRequest: [ [Function: transformRequest] ], transformResponse: [ [Function: transformResponse] ], timeout: 5000, adapter: [Function: httpAdapter], xsrfCookieName: 'XSRF-TOKEN', xsrfHeaderName: 'X-XSRF-TOKEN', maxContentLength: -1, maxBodyLength: -1, validateStatus: [Function: validateStatus], transitional: { silentJSONParsing: true, forcedJSONParsing: true, clarifyTimeoutError: false }, data: undefined }, request: <ref *1> Writable { _writableState: WritableState { objectMode: false, highWaterMark: 16384, finalCalled: false, needDrain: false, ending: false, ended: false, finished: false, destroyed: false, decodeStrings: true, defaultEncoding: 'utf8', length: 0, writing: false, corked: 0, sync: true, bufferProcessing: false, onwrite: [Function: bound onwrite], writecb: null, writelen: 0, afterWriteTickInfo: null, buffered: [], bufferedIndex: 0, allBuffers: true, allNoop: true, pendingcb: 0, constructed: true, prefinished: false, errorEmitted: false, emitClose: true, autoDestroy: true, errored: null, closed: false, closeEmitted: false, [Symbol(kOnFinished)]: [] }, _events: [Object: null prototype] { response: [Function: handleResponse], error: [Function: handleRequestError], socket: [Function: destroyOnTimeout] }, _eventsCount: 3, _maxListeners: undefined, _options: { maxRedirects: 21, maxBodyLength: 10485760, protocol: 'https:', path: '/api/books?filter[slug]=testpage', method: 'GET', headers: [Object], agent: undefined, agents: [Object], auth: undefined, hostname: 'URL.com', port: null, nativeProtocols: [Object], pathname: '/api/books', search: '?filter[slug]=testpage' }, _ended: true, _ending: true, _redirectCount: 0, _redirects: [], _requestBodyLength: 0, _requestBodyBuffers: [], _onNativeResponse: [Function (anonymous)], _currentRequest: ClientRequest { _events: [Object: null prototype], _eventsCount: 7, _maxListeners: undefined, outputData: [], outputSize: 0, writable: true, destroyed: false, _last: true, chunkedEncoding: false, shouldKeepAlive: false, maxRequestsOnConnectionReached: false, _defaultKeepAlive: true, useChunkedEncodingByDefault: false, sendDate: false, _removedConnection: false, _removedContLen: false, _removedTE: false, _contentLength: 0, _hasBody: true, _trailer: '', finished: true, _headerSent: true, _closed: false, socket: [TLSSocket], _header: 'GET /api/books?filter[slug]=testpage HTTP/1.1\r\n' + 'Accept: application/json, text/plain, */*\r\n' + 'Authorization: Token puN1AY6zEQ62CX0gNo3mTHoLW4O5WxYW:zojyPKBwFl5WfVssHQEV3g2UxjnclFVQ\r\n' + 'User-Agent: axios/0.21.4\r\n' + 'Host: URL.com\r\n' + 'Connection: close\r\n' + '\r\n', _keepAliveTimeout: 0, _onPendingData: [Function: nop], agent: [Agent], socketPath: undefined, method: 'GET', maxHeaderSize: undefined, insecureHTTPParser: undefined, path: '/api/books?filter[slug]=testpage', _ended: false, res: null, aborted: false, timeoutCb: null, upgradeOrConnect: false, parser: null, maxHeadersCount: null, reusedSocket: false, host: 'URL.com', protocol: 'https:', _redirectable: [Circular *1], [Symbol(kCapture)]: false, [Symbol(kNeedDrain)]: false, [Symbol(corked)]: 0, [Symbol(kOutHeaders)]: [Object: null prototype], [Symbol(kUniqueHeaders)]: null }, _currentUrl: 'URL.com/api/books?filter[slug]=testpage', _timeout: null, [Symbol(kCapture)]: false }, response: undefined, isAxiosError: true, toJSON: [Function: toJSON] } ``` </details>
Author
Owner

@ssddanbrown commented on GitHub (Oct 24, 2022):

Hi @mschoon85,
I'm guessing you're using some kind of self-signed certificate for your BookStack instance?
If you, you might need to either tweak the script to ignore certificate issues (Disable security measures) or add the used certificate to the certificate trust store that's used by NodeJS.

@ssddanbrown commented on GitHub (Oct 24, 2022): Hi @mschoon85, I'm guessing you're using some kind of self-signed certificate for your BookStack instance? If you, you might need to either tweak the script to ignore certificate issues (Disable security measures) or add the used certificate to the certificate trust store that's used by NodeJS.
Author
Owner

@mschoon85 commented on GitHub (Oct 25, 2022):

Hi @ssddanbrown,

I got it working by disabling the certificate check. I added "process.env["NODE_TLS_REJECT_UNAUTHORIZED"] = 0;" to index.js.
I can now add small word documents to Bookstack, however it looks like larger files timeout. I'm trying to upload a 67 pages and 43495 word file and get the following error:

Error: timeout of 5000ms exceeded
    at createError (D:\API scripts\node-docx-to-page\node_modules\axios\lib\core\createError.js:16:15)
    at RedirectableRequest.handleRequestTimeout (D:\API scripts\node-docx-to-page\node_modules\axios\lib\adapters\http.js:303:16)
    at RedirectableRequest.emit (node:events:513:28)
    at Timeout.<anonymous> (D:\API scripts\node-docx-to-page\node_modules\follow-redirects\index.js:169:12)
    at listOnTimeout (node:internal/timers:559:17)
    at processTimers (node:internal/timers:502:7) {
  config: {
    url: '/pages',
    method: 'post',
@mschoon85 commented on GitHub (Oct 25, 2022): Hi @ssddanbrown, I got it working by disabling the certificate check. I added "process.env["NODE_TLS_REJECT_UNAUTHORIZED"] = 0;" to index.js. I can now add small word documents to Bookstack, however it looks like larger files timeout. I'm trying to upload a 67 pages and 43495 word file and get the following error: ``` Error: timeout of 5000ms exceeded at createError (D:\API scripts\node-docx-to-page\node_modules\axios\lib\core\createError.js:16:15) at RedirectableRequest.handleRequestTimeout (D:\API scripts\node-docx-to-page\node_modules\axios\lib\adapters\http.js:303:16) at RedirectableRequest.emit (node:events:513:28) at Timeout.<anonymous> (D:\API scripts\node-docx-to-page\node_modules\follow-redirects\index.js:169:12) at listOnTimeout (node:internal/timers:559:17) at processTimers (node:internal/timers:502:7) { config: { url: '/pages', method: 'post', ```
Author
Owner

@ssddanbrown commented on GitHub (Oct 25, 2022):

Sounds like you'd need to increase the timeout found in this section of the code:

ed1748f060/node-docx-to-page/index.js (L34-L39)

@ssddanbrown commented on GitHub (Oct 25, 2022): Sounds like you'd need to increase the timeout found in this section of the code: https://github.com/BookStackApp/api-scripts/blob/ed1748f060aaa9504f1b8583c3fcda0ff0752bb4/node-docx-to-page/index.js#L34-L39
Author
Owner

@mschoon85 commented on GitHub (Oct 26, 2022):

@ssddanbrown Thanks, I got it working now. I also made a PowerShell script to import word documents a bit more easier. When the script is started a Windows pop up shows to select the word document and then the script will import it:

function Open-File([string] $initialDirectory){

    [System.Reflection.Assembly]::LoadWithPartialName("System.windows.forms") | Out-Null

    $OpenFileDialog = New-Object System.Windows.Forms.OpenFileDialog
    $OpenFileDialog.initialDirectory = "D:\Documents"
    $OpenFileDialog.filter = "All files (*.*)| *.*"
    $OpenFileDialog.ShowDialog() |  Out-Null

    return $OpenFileDialog.filename
} 

$OpenFile=Open-File $env:USERPROFILE 

if ($OpenFile -ne "") 
{
    echo "You choose FileName: $OpenFile" 
} 
else 
{
    echo "No File was chosen"
}


node index.js $OpenFile {bookname}

Instead of {bookname} enter the name of the book without the brackets. I'm going to make some improvements to the script, for example choosing which book the document should be uploaded to.

@mschoon85 commented on GitHub (Oct 26, 2022): @ssddanbrown Thanks, I got it working now. I also made a PowerShell script to import word documents a bit more easier. When the script is started a Windows pop up shows to select the word document and then the script will import it: ```` function Open-File([string] $initialDirectory){ [System.Reflection.Assembly]::LoadWithPartialName("System.windows.forms") | Out-Null $OpenFileDialog = New-Object System.Windows.Forms.OpenFileDialog $OpenFileDialog.initialDirectory = "D:\Documents" $OpenFileDialog.filter = "All files (*.*)| *.*" $OpenFileDialog.ShowDialog() | Out-Null return $OpenFileDialog.filename } $OpenFile=Open-File $env:USERPROFILE if ($OpenFile -ne "") { echo "You choose FileName: $OpenFile" } else { echo "No File was chosen" } node index.js $OpenFile {bookname} ```` Instead of {bookname} enter the name of the book without the brackets. I'm going to make some improvements to the script, for example choosing which book the document should be uploaded to.
Author
Owner

@mschoon85 commented on GitHub (Oct 26, 2022):

@ssddanbrown

If interested I completed my script. The script has to be saved as a .ps1 file and executed with Powershell. It will show a menu to choose which book the docx document is going to be uploaded to, after choosing the book a windows file explorer window will open up to browse to the document and select it. A filter is active so only docx documents are shown. After the import has been completed you will return to the menu to import other documents, to whatever book is needed.

To use the script you must change the following:
$OpenFileDialog.initialDirectory = "path to start browsing"
node --no-warnings "locationof\index.js" $OpenFile Book1

Important note: I'm not a programmer so things can most likely be improved, but at least it works and users can upload their own documents without using and creating the correct command line option themselves or contacting an administrator to do it for them. We have hundreds of documents to import, that's why it would be better that importing word documents would be a good thing to have within the Bookstack GUI. Users would then be able to import documents themselves without using the API, a custom made script like this, or bother me or other admins. Our users are not all technical enough to use Powershell or command line options, and for non-IT personal the usage of powershell and commandline is disabled through policy.

Example (Sorry for the Dutch language):
image

$Host.UI.RawUI.ForegroundColor = ($bckgrnd = 'darkGreen')

$GetInfo = {
function DisplayMenu {
Clear-Host
Write-Host @"
+================================================+
|    Choose a book to import the document        |
|   * Only Word documents in docx format *       | 
+================================================+
|                                                |
|    1) Book1                                    |
|    2) Book2                                    |
|    3) Book3                                    |
|    4) Book4                                    |
|    5) Book5                                    |
|    6) Book6                                    |
|    7) Book7                                    |
|    8) Book8                                    |
|    9) Book9                                    |
|    10) Book10                                  |
|    11) Book11                                  |
|                                                |
+================================================+

"@

$MENU = Read-Host "Book"
Switch ($MENU)



{
1 {
#OPTION1 - Book1
$OPTION1 = function Open-File([string] $initialDirectory){

    [System.Reflection.Assembly]::LoadWithPartialName("System.windows.forms") | Out-Null

    $OpenFileDialog = New-Object System.Windows.Forms.OpenFileDialog
    $OpenFileDialog.initialDirectory = "path to start browsing"
    $OpenFileDialog.filter = "Word Documents (*.docx)|*.docx"
    $OpenFileDialog.ShowDialog() |  Out-Null

    return $OpenFileDialog.filename
} 

$OpenFile=Open-File $env:USERPROFILE 

if ($OpenFile -ne "") 
{
    echo "You have chosen: $OpenFile" 
} 
else 
{
    echo "No file chosen"
}


node --no-warnings "locationof\index.js" $OpenFile Book1
write-host "`n"
Write-Host "Done! You will now automatically return to the menu"
Start-Sleep -Seconds 5
}




2 {
#OPTION2 - Book2
$OPTION2 = function Open-File([string] $initialDirectory){

    [System.Reflection.Assembly]::LoadWithPartialName("System.windows.forms") | Out-Null

    $OpenFileDialog = New-Object System.Windows.Forms.OpenFileDialog
    $OpenFileDialog.initialDirectory = "path to start browsing"
    $OpenFileDialog.filter = "Word Documents (*.docx)|*.docx"
    $OpenFileDialog.ShowDialog() |  Out-Null

    return $OpenFileDialog.filename
} 

$OpenFile=Open-File $env:USERPROFILE 

if ($OpenFile -ne "") 
{
    echo "You have chosen: $OpenFile" 
} 
else 
{
    echo "No file chosen"
}


node --no-warnings "locationof\index.js" $OpenFile Book2
write-host "`n"
Write-Host "Done! You will now automatically return to the menu"
Start-Sleep -Seconds 5
}



3 {
#OPTION3 - Book3
$OPTION3 = function Open-File([string] $initialDirectory){

    [System.Reflection.Assembly]::LoadWithPartialName("System.windows.forms") | Out-Null

    $OpenFileDialog = New-Object System.Windows.Forms.OpenFileDialog
    $OpenFileDialog.initialDirectory = "path to start browsing"
    $OpenFileDialog.filter = "Word Documents (*.docx)|*.docx"
    $OpenFileDialog.ShowDialog() |  Out-Null

    return $OpenFileDialog.filename
} 

$OpenFile=Open-File $env:USERPROFILE 

if ($OpenFile -ne "") 
{
    echo "You have chosen: $OpenFile" 
} 
else 
{
    echo "No file chosen"
}


node --no-warnings "locationof\index.js" $OpenFile Book3
write-host "`n"
Write-Host "Done! You will now automatically return to the menu"
Start-Sleep -Seconds 5
}



4 {
#OPTION4 - Book4
$OPTION4 = function Open-File([string] $initialDirectory){

    [System.Reflection.Assembly]::LoadWithPartialName("System.windows.forms") | Out-Null

    $OpenFileDialog = New-Object System.Windows.Forms.OpenFileDialog
    $OpenFileDialog.initialDirectory = "path to start browsing"
    $OpenFileDialog.filter = "Word Documents (*.docx)|*.docx"
    $OpenFileDialog.ShowDialog() |  Out-Null

    return $OpenFileDialog.filename
} 

$OpenFile=Open-File $env:USERPROFILE 

if ($OpenFile -ne "") 
{
    echo "You have chosen: $OpenFile" 
} 
else 
{
    echo "No file chosen"
}


node --no-warnings "locationof\index.js" $OpenFile Book4
write-host "`n"
Write-Host "Done! You will now automatically return to the menu"
Start-Sleep -Seconds 5
}




5 {
#OPTION5 - Book5
$OPTION5 = function Open-File([string] $initialDirectory){

    [System.Reflection.Assembly]::LoadWithPartialName("System.windows.forms") | Out-Null

    $OpenFileDialog = New-Object System.Windows.Forms.OpenFileDialog
    $OpenFileDialog.initialDirectory = "path to start browsing"
    $OpenFileDialog.filter = "Word Documents (*.docx)|*.docx"
    $OpenFileDialog.ShowDialog() |  Out-Null

    return $OpenFileDialog.filename
} 

$OpenFile=Open-File $env:USERPROFILE 

if ($OpenFile -ne "") 
{
    echo "You have chosen: $OpenFile" 
} 
else 
{
    echo "No file chosen"
}


node --no-warnings "locationof\index.js" $OpenFile Book5
write-host "`n"
Write-Host "Done! You will now automatically return to the menu"
Start-Sleep -Seconds 5
}




6 {
#OPTION6 - Book6
$OPTION6 = function Open-File([string] $initialDirectory){

    [System.Reflection.Assembly]::LoadWithPartialName("System.windows.forms") | Out-Null

    $OpenFileDialog = New-Object System.Windows.Forms.OpenFileDialog
    $OpenFileDialog.initialDirectory = "path to start browsing"
    $OpenFileDialog.filter = "Word Documents (*.docx)|*.docx"
    $OpenFileDialog.ShowDialog() |  Out-Null

    return $OpenFileDialog.filename
} 

$OpenFile=Open-File $env:USERPROFILE 

if ($OpenFile -ne "") 
{
    echo "You have chosen: $OpenFile" 
} 
else 
{
    echo "No file chosen"
}


node --no-warnings "locationof\index.js" $OpenFile Book6
write-host "`n"
Write-Host "Done! You will now automatically return to the menu"
Start-Sleep -Seconds 5
}




7 {
#OPTION7 - Book7
$OPTION7 = function Open-File([string] $initialDirectory){

    [System.Reflection.Assembly]::LoadWithPartialName("System.windows.forms") | Out-Null

    $OpenFileDialog = New-Object System.Windows.Forms.OpenFileDialog
    $OpenFileDialog.initialDirectory = "path to start browsing"
    $OpenFileDialog.filter = "Word Documents (*.docx)|*.docx"
    $OpenFileDialog.ShowDialog() |  Out-Null

    return $OpenFileDialog.filename
} 

$OpenFile=Open-File $env:USERPROFILE 

if ($OpenFile -ne "") 
{
    echo "You have chosen: $OpenFile" 
} 
else 
{
    echo "No file chosen"
}


node --no-warnings "locationof\index.js" $OpenFile Book7
write-host "`n"
Write-Host "Done! You will now automatically return to the menu"
Start-Sleep -Seconds 5
}




8 {
#OPTION8 - Book8
$OPTION8 = function Open-File([string] $initialDirectory){

    [System.Reflection.Assembly]::LoadWithPartialName("System.windows.forms") | Out-Null

    $OpenFileDialog = New-Object System.Windows.Forms.OpenFileDialog
    $OpenFileDialog.initialDirectory = "path to start browsing"
    $OpenFileDialog.filter = "Word Documents (*.docx)|*.docx"
    $OpenFileDialog.ShowDialog() |  Out-Null

    return $OpenFileDialog.filename
} 

$OpenFile=Open-File $env:USERPROFILE 

if ($OpenFile -ne "") 
{
    echo "You have chosen: $OpenFile" 
} 
else 
{
    echo "No file chosen"
}


node --no-warnings "locationof\index.js" $OpenFile Book8
write-host "`n"
Write-Host "Done! You will now automatically return to the menu"
Start-Sleep -Seconds 5
}




9 {
#OPTION9 - Book9
$OPTION9 = function Open-File([string] $initialDirectory){

    [System.Reflection.Assembly]::LoadWithPartialName("System.windows.forms") | Out-Null

    $OpenFileDialog = New-Object System.Windows.Forms.OpenFileDialog
    $OpenFileDialog.initialDirectory = "path to start browsing"
    $OpenFileDialog.filter = "Word Documents (*.docx)|*.docx"
    $OpenFileDialog.ShowDialog() |  Out-Null

    return $OpenFileDialog.filename
} 

$OpenFile=Open-File $env:USERPROFILE 

if ($OpenFile -ne "") 
{
    echo "You have chosen: $OpenFile" 
} 
else 
{
    echo "No file chosen"
}


node --no-warnings "locationof\index.js" $OpenFile Book9
write-host "`n"
Write-Host "Done! You will now automatically return to the menu"
Start-Sleep -Seconds 5
}




10 {
#OPTION10 - Book10
$OPTION10 = function Open-File([string] $initialDirectory){

    [System.Reflection.Assembly]::LoadWithPartialName("System.windows.forms") | Out-Null

    $OpenFileDialog = New-Object System.Windows.Forms.OpenFileDialog
    $OpenFileDialog.initialDirectory = "path to start browsing"
    $OpenFileDialog.filter = "Word Documents (*.docx)|*.docx"
    $OpenFileDialog.ShowDialog() |  Out-Null

    return $OpenFileDialog.filename
} 

$OpenFile=Open-File $env:USERPROFILE 

if ($OpenFile -ne "") 
{
    echo "You have chosen: $OpenFile" 
} 
else 
{
    echo "No file chosen"
}


node --no-warnings "locationof\index.js" $OpenFile Book10
write-host "`n"
Write-Host "Done! You will now automatically return to the menu"
Start-Sleep -Seconds 5
}





11 {
#OPTION11 - Book11
$OPTION11 = function Open-File([string] $initialDirectory){

    [System.Reflection.Assembly]::LoadWithPartialName("System.windows.forms") | Out-Null

    $OpenFileDialog = New-Object System.Windows.Forms.OpenFileDialog
    $OpenFileDialog.initialDirectory = "path to start browsing"
    $OpenFileDialog.filter = "Word Documents (*.docx)|*.docx"
    $OpenFileDialog.ShowDialog() |  Out-Null

    return $OpenFileDialog.filename
} 

$OpenFile=Open-File $env:USERPROFILE 

if ($OpenFile -ne "") 
{
    echo "You have chosen: $OpenFile" 
} 
else 
{
    echo "No file chosen"
}


node --no-warnings "locationof\index.js" $OpenFile book11
write-host "`n"
Write-Host "Done! You will now automatically return to the menu"
Start-Sleep -Seconds 5
}



default {
#DEFAULT OPTION
Write-Host "Option not available"
Start-Sleep -Seconds 2
DisplayMenu
}
}
}
DisplayMenu

 .$GetInfo
 }

&$GetInfo
@mschoon85 commented on GitHub (Oct 26, 2022): @ssddanbrown If interested I completed my script. The script has to be saved as a .ps1 file and executed with Powershell. It will show a menu to choose which book the docx document is going to be uploaded to, after choosing the book a windows file explorer window will open up to browse to the document and select it. A filter is active so only docx documents are shown. After the import has been completed you will return to the menu to import other documents, to whatever book is needed. To use the script you must change the following: $OpenFileDialog.initialDirectory = "**path to start browsing**" node --no-warnings "**locationof\index.js**" $OpenFile **Book1** Important note: I'm not a programmer so things can most likely be improved, but at least it works and users can upload their own documents without using and creating the correct command line option themselves or contacting an administrator to do it for them. We have hundreds of documents to import, that's why it would be better that importing word documents would be a good thing to have within the Bookstack GUI. Users would then be able to import documents themselves without using the API, a custom made script like this, or bother me or other admins. Our users are not all technical enough to use Powershell or command line options, and for non-IT personal the usage of powershell and commandline is disabled through policy. Example (Sorry for the Dutch language): ![image](https://user-images.githubusercontent.com/96066244/198030747-975b57ea-b274-4ffb-88ac-cbf50d244e6c.png) ``` $Host.UI.RawUI.ForegroundColor = ($bckgrnd = 'darkGreen') $GetInfo = { function DisplayMenu { Clear-Host Write-Host @" +================================================+ | Choose a book to import the document | | * Only Word documents in docx format * | +================================================+ | | | 1) Book1 | | 2) Book2 | | 3) Book3 | | 4) Book4 | | 5) Book5 | | 6) Book6 | | 7) Book7 | | 8) Book8 | | 9) Book9 | | 10) Book10 | | 11) Book11 | | | +================================================+ "@ $MENU = Read-Host "Book" Switch ($MENU) { 1 { #OPTION1 - Book1 $OPTION1 = function Open-File([string] $initialDirectory){ [System.Reflection.Assembly]::LoadWithPartialName("System.windows.forms") | Out-Null $OpenFileDialog = New-Object System.Windows.Forms.OpenFileDialog $OpenFileDialog.initialDirectory = "path to start browsing" $OpenFileDialog.filter = "Word Documents (*.docx)|*.docx" $OpenFileDialog.ShowDialog() | Out-Null return $OpenFileDialog.filename } $OpenFile=Open-File $env:USERPROFILE if ($OpenFile -ne "") { echo "You have chosen: $OpenFile" } else { echo "No file chosen" } node --no-warnings "locationof\index.js" $OpenFile Book1 write-host "`n" Write-Host "Done! You will now automatically return to the menu" Start-Sleep -Seconds 5 } 2 { #OPTION2 - Book2 $OPTION2 = function Open-File([string] $initialDirectory){ [System.Reflection.Assembly]::LoadWithPartialName("System.windows.forms") | Out-Null $OpenFileDialog = New-Object System.Windows.Forms.OpenFileDialog $OpenFileDialog.initialDirectory = "path to start browsing" $OpenFileDialog.filter = "Word Documents (*.docx)|*.docx" $OpenFileDialog.ShowDialog() | Out-Null return $OpenFileDialog.filename } $OpenFile=Open-File $env:USERPROFILE if ($OpenFile -ne "") { echo "You have chosen: $OpenFile" } else { echo "No file chosen" } node --no-warnings "locationof\index.js" $OpenFile Book2 write-host "`n" Write-Host "Done! You will now automatically return to the menu" Start-Sleep -Seconds 5 } 3 { #OPTION3 - Book3 $OPTION3 = function Open-File([string] $initialDirectory){ [System.Reflection.Assembly]::LoadWithPartialName("System.windows.forms") | Out-Null $OpenFileDialog = New-Object System.Windows.Forms.OpenFileDialog $OpenFileDialog.initialDirectory = "path to start browsing" $OpenFileDialog.filter = "Word Documents (*.docx)|*.docx" $OpenFileDialog.ShowDialog() | Out-Null return $OpenFileDialog.filename } $OpenFile=Open-File $env:USERPROFILE if ($OpenFile -ne "") { echo "You have chosen: $OpenFile" } else { echo "No file chosen" } node --no-warnings "locationof\index.js" $OpenFile Book3 write-host "`n" Write-Host "Done! You will now automatically return to the menu" Start-Sleep -Seconds 5 } 4 { #OPTION4 - Book4 $OPTION4 = function Open-File([string] $initialDirectory){ [System.Reflection.Assembly]::LoadWithPartialName("System.windows.forms") | Out-Null $OpenFileDialog = New-Object System.Windows.Forms.OpenFileDialog $OpenFileDialog.initialDirectory = "path to start browsing" $OpenFileDialog.filter = "Word Documents (*.docx)|*.docx" $OpenFileDialog.ShowDialog() | Out-Null return $OpenFileDialog.filename } $OpenFile=Open-File $env:USERPROFILE if ($OpenFile -ne "") { echo "You have chosen: $OpenFile" } else { echo "No file chosen" } node --no-warnings "locationof\index.js" $OpenFile Book4 write-host "`n" Write-Host "Done! You will now automatically return to the menu" Start-Sleep -Seconds 5 } 5 { #OPTION5 - Book5 $OPTION5 = function Open-File([string] $initialDirectory){ [System.Reflection.Assembly]::LoadWithPartialName("System.windows.forms") | Out-Null $OpenFileDialog = New-Object System.Windows.Forms.OpenFileDialog $OpenFileDialog.initialDirectory = "path to start browsing" $OpenFileDialog.filter = "Word Documents (*.docx)|*.docx" $OpenFileDialog.ShowDialog() | Out-Null return $OpenFileDialog.filename } $OpenFile=Open-File $env:USERPROFILE if ($OpenFile -ne "") { echo "You have chosen: $OpenFile" } else { echo "No file chosen" } node --no-warnings "locationof\index.js" $OpenFile Book5 write-host "`n" Write-Host "Done! You will now automatically return to the menu" Start-Sleep -Seconds 5 } 6 { #OPTION6 - Book6 $OPTION6 = function Open-File([string] $initialDirectory){ [System.Reflection.Assembly]::LoadWithPartialName("System.windows.forms") | Out-Null $OpenFileDialog = New-Object System.Windows.Forms.OpenFileDialog $OpenFileDialog.initialDirectory = "path to start browsing" $OpenFileDialog.filter = "Word Documents (*.docx)|*.docx" $OpenFileDialog.ShowDialog() | Out-Null return $OpenFileDialog.filename } $OpenFile=Open-File $env:USERPROFILE if ($OpenFile -ne "") { echo "You have chosen: $OpenFile" } else { echo "No file chosen" } node --no-warnings "locationof\index.js" $OpenFile Book6 write-host "`n" Write-Host "Done! You will now automatically return to the menu" Start-Sleep -Seconds 5 } 7 { #OPTION7 - Book7 $OPTION7 = function Open-File([string] $initialDirectory){ [System.Reflection.Assembly]::LoadWithPartialName("System.windows.forms") | Out-Null $OpenFileDialog = New-Object System.Windows.Forms.OpenFileDialog $OpenFileDialog.initialDirectory = "path to start browsing" $OpenFileDialog.filter = "Word Documents (*.docx)|*.docx" $OpenFileDialog.ShowDialog() | Out-Null return $OpenFileDialog.filename } $OpenFile=Open-File $env:USERPROFILE if ($OpenFile -ne "") { echo "You have chosen: $OpenFile" } else { echo "No file chosen" } node --no-warnings "locationof\index.js" $OpenFile Book7 write-host "`n" Write-Host "Done! You will now automatically return to the menu" Start-Sleep -Seconds 5 } 8 { #OPTION8 - Book8 $OPTION8 = function Open-File([string] $initialDirectory){ [System.Reflection.Assembly]::LoadWithPartialName("System.windows.forms") | Out-Null $OpenFileDialog = New-Object System.Windows.Forms.OpenFileDialog $OpenFileDialog.initialDirectory = "path to start browsing" $OpenFileDialog.filter = "Word Documents (*.docx)|*.docx" $OpenFileDialog.ShowDialog() | Out-Null return $OpenFileDialog.filename } $OpenFile=Open-File $env:USERPROFILE if ($OpenFile -ne "") { echo "You have chosen: $OpenFile" } else { echo "No file chosen" } node --no-warnings "locationof\index.js" $OpenFile Book8 write-host "`n" Write-Host "Done! You will now automatically return to the menu" Start-Sleep -Seconds 5 } 9 { #OPTION9 - Book9 $OPTION9 = function Open-File([string] $initialDirectory){ [System.Reflection.Assembly]::LoadWithPartialName("System.windows.forms") | Out-Null $OpenFileDialog = New-Object System.Windows.Forms.OpenFileDialog $OpenFileDialog.initialDirectory = "path to start browsing" $OpenFileDialog.filter = "Word Documents (*.docx)|*.docx" $OpenFileDialog.ShowDialog() | Out-Null return $OpenFileDialog.filename } $OpenFile=Open-File $env:USERPROFILE if ($OpenFile -ne "") { echo "You have chosen: $OpenFile" } else { echo "No file chosen" } node --no-warnings "locationof\index.js" $OpenFile Book9 write-host "`n" Write-Host "Done! You will now automatically return to the menu" Start-Sleep -Seconds 5 } 10 { #OPTION10 - Book10 $OPTION10 = function Open-File([string] $initialDirectory){ [System.Reflection.Assembly]::LoadWithPartialName("System.windows.forms") | Out-Null $OpenFileDialog = New-Object System.Windows.Forms.OpenFileDialog $OpenFileDialog.initialDirectory = "path to start browsing" $OpenFileDialog.filter = "Word Documents (*.docx)|*.docx" $OpenFileDialog.ShowDialog() | Out-Null return $OpenFileDialog.filename } $OpenFile=Open-File $env:USERPROFILE if ($OpenFile -ne "") { echo "You have chosen: $OpenFile" } else { echo "No file chosen" } node --no-warnings "locationof\index.js" $OpenFile Book10 write-host "`n" Write-Host "Done! You will now automatically return to the menu" Start-Sleep -Seconds 5 } 11 { #OPTION11 - Book11 $OPTION11 = function Open-File([string] $initialDirectory){ [System.Reflection.Assembly]::LoadWithPartialName("System.windows.forms") | Out-Null $OpenFileDialog = New-Object System.Windows.Forms.OpenFileDialog $OpenFileDialog.initialDirectory = "path to start browsing" $OpenFileDialog.filter = "Word Documents (*.docx)|*.docx" $OpenFileDialog.ShowDialog() | Out-Null return $OpenFileDialog.filename } $OpenFile=Open-File $env:USERPROFILE if ($OpenFile -ne "") { echo "You have chosen: $OpenFile" } else { echo "No file chosen" } node --no-warnings "locationof\index.js" $OpenFile book11 write-host "`n" Write-Host "Done! You will now automatically return to the menu" Start-Sleep -Seconds 5 } default { #DEFAULT OPTION Write-Host "Option not available" Start-Sleep -Seconds 2 DisplayMenu } } } DisplayMenu .$GetInfo } &$GetInfo ```
Author
Owner

@ssddanbrown commented on GitHub (Oct 27, 2022):

Good to hear you got things working, and thanks for sharing the script.
I will therefore close this off.

@ssddanbrown commented on GitHub (Oct 27, 2022): Good to hear you got things working, and thanks for sharing the script. I will therefore close this off.
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: starred/BookStack#3301